From 5f84270d773746e22cb40d33498d47a0e560e6af Mon Sep 17 00:00:00 2001 From: Jordi Fernandez Date: Thu, 10 Oct 2024 07:59:19 +0200 Subject: [PATCH 1/7] Remove quoted type constraints (#1412) Type constraints in quotes was required in Terraform 0.11 and earlier, but that form is now deprecated and will be removed in a future version of Terraform. For example: variable "control_plane_id" { type = "string" default = "YOUR_CONTROL_PLANE_ID" } should be variable "control_plane_id" { type = string default = "YOUR_CONTROL_PLANE_ID" } if the quotes are present, an error is shown during terraform apply. --- kong2tf/builder_default_terraform.go | 2 +- kong2tf/testdata/ca-certificate-output-expected.tf | 2 +- kong2tf/testdata/certificate-sni-output-expected.tf | 2 +- kong2tf/testdata/consumer-acl-output-expected.tf | 2 +- kong2tf/testdata/consumer-basic-auth-output-expected.tf | 2 +- kong2tf/testdata/consumer-group-output-expected.tf | 2 +- kong2tf/testdata/consumer-group-plugin-output-expected.tf | 2 +- kong2tf/testdata/consumer-hmac-auth-output-expected.tf | 2 +- kong2tf/testdata/consumer-jwt-output-expected.tf | 2 +- kong2tf/testdata/consumer-jwt-output-with-imports-expected.tf | 2 +- kong2tf/testdata/consumer-key-auth-output-expected.tf | 2 +- kong2tf/testdata/consumer-no-auth-output-expected.tf | 2 +- kong2tf/testdata/consumer-plugin-output-expected.tf | 2 +- kong2tf/testdata/global-plugin-oidc-output-expected.tf | 2 +- kong2tf/testdata/global-plugin-rate-limiting-output-expected.tf | 2 +- kong2tf/testdata/route-output-expected.tf | 2 +- kong2tf/testdata/route-plugin-output-expected.tf | 2 +- kong2tf/testdata/service-output-expected.tf | 2 +- kong2tf/testdata/service-plugin-output-expected.tf | 2 +- kong2tf/testdata/upstream-target-output-expected.tf | 2 +- kong2tf/testdata/vault-output-expected.tf | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/kong2tf/builder_default_terraform.go b/kong2tf/builder_default_terraform.go index fb11d791f..5c34dc73a 100644 --- a/kong2tf/builder_default_terraform.go +++ b/kong2tf/builder_default_terraform.go @@ -40,7 +40,7 @@ func (b *DefaultTerraformBuider) buildControlPlaneVar(controlPlaneID *string) { cpID = *controlPlaneID } b.content += fmt.Sprintf(`variable "control_plane_id" { - type = "string" + type = string default = "%s" }`, cpID) + "\n\n" } diff --git a/kong2tf/testdata/ca-certificate-output-expected.tf b/kong2tf/testdata/ca-certificate-output-expected.tf index 90d22b371..72a42e885 100644 --- a/kong2tf/testdata/ca-certificate-output-expected.tf +++ b/kong2tf/testdata/ca-certificate-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/certificate-sni-output-expected.tf b/kong2tf/testdata/certificate-sni-output-expected.tf index 28bc8f451..9725ec79c 100644 --- a/kong2tf/testdata/certificate-sni-output-expected.tf +++ b/kong2tf/testdata/certificate-sni-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/consumer-acl-output-expected.tf b/kong2tf/testdata/consumer-acl-output-expected.tf index daee55d7b..60fe181f7 100644 --- a/kong2tf/testdata/consumer-acl-output-expected.tf +++ b/kong2tf/testdata/consumer-acl-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/consumer-basic-auth-output-expected.tf b/kong2tf/testdata/consumer-basic-auth-output-expected.tf index c46d19c61..d22995022 100644 --- a/kong2tf/testdata/consumer-basic-auth-output-expected.tf +++ b/kong2tf/testdata/consumer-basic-auth-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/consumer-group-output-expected.tf b/kong2tf/testdata/consumer-group-output-expected.tf index 7d4ceca0e..22454a2ca 100644 --- a/kong2tf/testdata/consumer-group-output-expected.tf +++ b/kong2tf/testdata/consumer-group-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/consumer-group-plugin-output-expected.tf b/kong2tf/testdata/consumer-group-plugin-output-expected.tf index 7a8b82d2d..7503a13b5 100644 --- a/kong2tf/testdata/consumer-group-plugin-output-expected.tf +++ b/kong2tf/testdata/consumer-group-plugin-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/consumer-hmac-auth-output-expected.tf b/kong2tf/testdata/consumer-hmac-auth-output-expected.tf index 24675be71..89132e708 100644 --- a/kong2tf/testdata/consumer-hmac-auth-output-expected.tf +++ b/kong2tf/testdata/consumer-hmac-auth-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/consumer-jwt-output-expected.tf b/kong2tf/testdata/consumer-jwt-output-expected.tf index b126ce540..1584560d8 100644 --- a/kong2tf/testdata/consumer-jwt-output-expected.tf +++ b/kong2tf/testdata/consumer-jwt-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/consumer-jwt-output-with-imports-expected.tf b/kong2tf/testdata/consumer-jwt-output-with-imports-expected.tf index 698018209..90fe5429f 100644 --- a/kong2tf/testdata/consumer-jwt-output-with-imports-expected.tf +++ b/kong2tf/testdata/consumer-jwt-output-with-imports-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "abc-123" } diff --git a/kong2tf/testdata/consumer-key-auth-output-expected.tf b/kong2tf/testdata/consumer-key-auth-output-expected.tf index 753478f3c..b5d23f7e6 100644 --- a/kong2tf/testdata/consumer-key-auth-output-expected.tf +++ b/kong2tf/testdata/consumer-key-auth-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/consumer-no-auth-output-expected.tf b/kong2tf/testdata/consumer-no-auth-output-expected.tf index d218747a3..ffebc4521 100644 --- a/kong2tf/testdata/consumer-no-auth-output-expected.tf +++ b/kong2tf/testdata/consumer-no-auth-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/consumer-plugin-output-expected.tf b/kong2tf/testdata/consumer-plugin-output-expected.tf index 0650f0cad..3e6498557 100644 --- a/kong2tf/testdata/consumer-plugin-output-expected.tf +++ b/kong2tf/testdata/consumer-plugin-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/global-plugin-oidc-output-expected.tf b/kong2tf/testdata/global-plugin-oidc-output-expected.tf index 0b402b1f4..d320bc21f 100644 --- a/kong2tf/testdata/global-plugin-oidc-output-expected.tf +++ b/kong2tf/testdata/global-plugin-oidc-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/global-plugin-rate-limiting-output-expected.tf b/kong2tf/testdata/global-plugin-rate-limiting-output-expected.tf index 5a19a1acb..4b66fc313 100644 --- a/kong2tf/testdata/global-plugin-rate-limiting-output-expected.tf +++ b/kong2tf/testdata/global-plugin-rate-limiting-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/route-output-expected.tf b/kong2tf/testdata/route-output-expected.tf index bc879c61d..e01cf1955 100644 --- a/kong2tf/testdata/route-output-expected.tf +++ b/kong2tf/testdata/route-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/route-plugin-output-expected.tf b/kong2tf/testdata/route-plugin-output-expected.tf index 662d8b4ea..f12ff2add 100644 --- a/kong2tf/testdata/route-plugin-output-expected.tf +++ b/kong2tf/testdata/route-plugin-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/service-output-expected.tf b/kong2tf/testdata/service-output-expected.tf index 59128051e..39791e6a4 100644 --- a/kong2tf/testdata/service-output-expected.tf +++ b/kong2tf/testdata/service-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/service-plugin-output-expected.tf b/kong2tf/testdata/service-plugin-output-expected.tf index ea871a4f1..d52c70693 100644 --- a/kong2tf/testdata/service-plugin-output-expected.tf +++ b/kong2tf/testdata/service-plugin-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/upstream-target-output-expected.tf b/kong2tf/testdata/upstream-target-output-expected.tf index fdb9eb0a1..25b2f2d70 100644 --- a/kong2tf/testdata/upstream-target-output-expected.tf +++ b/kong2tf/testdata/upstream-target-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } diff --git a/kong2tf/testdata/vault-output-expected.tf b/kong2tf/testdata/vault-output-expected.tf index 1c1af8d8b..1f5e197da 100644 --- a/kong2tf/testdata/vault-output-expected.tf +++ b/kong2tf/testdata/vault-output-expected.tf @@ -1,5 +1,5 @@ variable "control_plane_id" { - type = "string" + type = string default = "YOUR_CONTROL_PLANE_ID" } From c1a83b4ee39e2a8dce18ea6d870f8e50d38a0ea4 Mon Sep 17 00:00:00 2001 From: Jordi Fernandez Date: Fri, 18 Oct 2024 11:44:21 +0200 Subject: [PATCH 2/7] Improve KIC integration testing (#1235) - Granular tests based on each resource type - Integration test deploys generated manifests to k8s cluster - Refactor code to add annotations for tags - Fix consumer group plugin bug - Inform plugin attributes: enabled, runon, ordering, protocols - Generate external service when host is informed and there is no upstream match - Increased test coverage KIC versions 2.12, 3.0, 3.1, 3.2, 3.3 --- go.mod | 57 +- go.sum | 194 +- kong2kic/builder_v2_gw_api.go | 2 +- kong2kic/builder_v3_gw_api.go | 2 +- kong2kic/ca_certificate.go | 21 +- kong2kic/certificate.go | 23 +- kong2kic/consumer.go | 325 +- kong2kic/consumer_credentials.go | 137 + kong2kic/consumer_group.go | 122 +- kong2kic/global_plugin.go | 52 +- kong2kic/kong2kic_test.go | 489 +- kong2kic/route.go | 645 +- kong2kic/service.go | 210 +- kong2kic/testdata/README.md | 64 + kong2kic/testdata/ca-certificate-input.yaml | 49 + .../ca-certificate-output-expected.yaml | 69 + kong2kic/testdata/certificate-input.yaml | 146 + .../testdata/certificate-output-expected.yaml | 158 + kong2kic/testdata/consumer-group-input.yaml | 19 + .../consumer-group-output-expected.yaml | 32 + kong2kic/testdata/consumer-input.yaml | 43 + .../testdata/consumer-v2-output-expected.yaml | 94 + .../testdata/consumer-v3-output-expected.yaml | 99 + kong2kic/testdata/gateway-api-crd.yaml | 7137 +++++++++++++++++ kong2kic/testdata/global-plugin-input.yaml | 12 + .../global-plugin-output-expected.yaml | 15 + .../kicv2_gateway/output-expected.json | 1483 ---- .../kicv2_gateway/output-expected.yaml | 1181 --- .../kicv2_ingress/output-expected.json | 750 -- .../kicv2_ingress/output-expected.yaml | 737 -- .../kicv3_gateway/output-expected.json | 1486 ---- .../kicv3_gateway/output-expected.yaml | 1180 --- .../kicv3_ingress/output-expected.json | 753 -- .../kicv3_ingress/output-expected.yaml | 736 -- .../testdata/route-gw-v2-output-expected.yaml | 189 + .../testdata/route-gw-v3-output-expected.yaml | 189 + .../route-ingress-output-expected.yaml | 136 + kong2kic/testdata/route-input.yaml | 47 + kong2kic/testdata/service-input.yaml | 40 + .../testdata/service-output-expected.yaml | 61 + kong2kic/testdata/upstream-input.yaml | 82 + .../testdata/upstream-v2-output-expected.yaml | 95 + .../testdata/upstream-v3-output-expected.yaml | 91 + kong2kic/upstream.go | 397 +- kong2kic/utils.go | 94 + 45 files changed, 10464 insertions(+), 9479 deletions(-) create mode 100644 kong2kic/consumer_credentials.go create mode 100644 kong2kic/testdata/README.md create mode 100644 kong2kic/testdata/ca-certificate-input.yaml create mode 100644 kong2kic/testdata/ca-certificate-output-expected.yaml create mode 100644 kong2kic/testdata/certificate-input.yaml create mode 100644 kong2kic/testdata/certificate-output-expected.yaml create mode 100644 kong2kic/testdata/consumer-group-input.yaml create mode 100644 kong2kic/testdata/consumer-group-output-expected.yaml create mode 100644 kong2kic/testdata/consumer-input.yaml create mode 100644 kong2kic/testdata/consumer-v2-output-expected.yaml create mode 100644 kong2kic/testdata/consumer-v3-output-expected.yaml create mode 100644 kong2kic/testdata/gateway-api-crd.yaml create mode 100644 kong2kic/testdata/global-plugin-input.yaml create mode 100644 kong2kic/testdata/global-plugin-output-expected.yaml delete mode 100644 kong2kic/testdata/kicv2_gateway/output-expected.json delete mode 100644 kong2kic/testdata/kicv2_gateway/output-expected.yaml delete mode 100644 kong2kic/testdata/kicv2_ingress/output-expected.json delete mode 100644 kong2kic/testdata/kicv2_ingress/output-expected.yaml delete mode 100644 kong2kic/testdata/kicv3_gateway/output-expected.json delete mode 100644 kong2kic/testdata/kicv3_gateway/output-expected.yaml delete mode 100644 kong2kic/testdata/kicv3_ingress/output-expected.json delete mode 100644 kong2kic/testdata/kicv3_ingress/output-expected.yaml create mode 100644 kong2kic/testdata/route-gw-v2-output-expected.yaml create mode 100644 kong2kic/testdata/route-gw-v3-output-expected.yaml create mode 100644 kong2kic/testdata/route-ingress-output-expected.yaml create mode 100644 kong2kic/testdata/route-input.yaml create mode 100644 kong2kic/testdata/service-input.yaml create mode 100644 kong2kic/testdata/service-output-expected.yaml create mode 100644 kong2kic/testdata/upstream-input.yaml create mode 100644 kong2kic/testdata/upstream-v2-output-expected.yaml create mode 100644 kong2kic/testdata/upstream-v3-output-expected.yaml create mode 100644 kong2kic/utils.go diff --git a/go.mod b/go.mod index 05c05f8c1..99c50d77f 100644 --- a/go.mod +++ b/go.mod @@ -18,42 +18,94 @@ require ( github.com/mitchellh/go-homedir v1.1.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.18.2 + github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 golang.org/x/sync v0.8.0 k8s.io/api v0.31.0 k8s.io/apiextensions-apiserver v0.31.0 k8s.io/apimachinery v0.31.0 + k8s.io/client-go v0.31.0 k8s.io/code-generator v0.31.0 sigs.k8s.io/gateway-api v1.1.0 sigs.k8s.io/yaml v1.4.0 ) require ( + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/MakeNowJust/heredoc v1.0.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/avast/retry-go/v4 v4.6.0 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/buger/jsonparser v1.1.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/chai2010/gettext-go v1.0.2 // indirect + github.com/distribution/reference v0.5.0 // indirect + github.com/docker/docker v26.1.4+incompatible // indirect + github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.12.0 // indirect + github.com/evanphx/json-patch v5.9.0+incompatible // indirect + github.com/evanphx/json-patch/v5 v5.9.0 // indirect + github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect + github.com/fatih/camelcase v1.0.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fvbommel/sortorder v1.1.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/go-errors/errors v1.4.2 // indirect + github.com/google/btree v1.1.2 // indirect github.com/google/go-querystring v1.1.0 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.1 // indirect + github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect github.com/hashicorp/go-memdb v1.3.4 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/spdystream v0.4.0 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/onsi/ginkgo v1.16.5 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pb33f/doctor v0.0.6 // indirect github.com/pb33f/libopenapi v0.16.13 // indirect github.com/pb33f/libopenapi-validator v0.0.49 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sethvargo/go-password v0.3.0 // indirect github.com/shirou/gopsutil/v3 v3.24.5 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/ssgelm/cookiejarparser v1.0.1 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect + github.com/xlab/treeprint v1.2.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect + go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/time v0.5.0 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + k8s.io/cli-runtime v0.30.1 // indirect + k8s.io/component-base v0.31.0 // indirect k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 // indirect + k8s.io/kubectl v0.30.1 // indirect + sigs.k8s.io/kind v0.23.0 // indirect + sigs.k8s.io/kustomize/api v0.17.2 // indirect + sigs.k8s.io/kustomize/kyaml v0.17.1 // indirect ) require ( @@ -96,6 +148,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/kong/go-slugify v1.0.0 // indirect github.com/kong/kubernetes-ingress-controller/v3 v3.2.4 + github.com/kong/kubernetes-testing-framework v0.47.1 github.com/kong/semver/v4 v4.0.1 // indirect github.com/lithammer/fuzzysearch v1.1.8 // indirect github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect @@ -108,7 +161,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mozillazg/go-unidecode v0.2.0 // indirect - github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect github.com/pterm/pterm v0.12.79 // indirect diff --git a/go.sum b/go.sum index 53dee8c78..4cd80a5b7 100644 --- a/go.sum +++ b/go.sum @@ -6,14 +6,20 @@ atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs= atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Kong/go-diff v1.2.2 h1:KKKaqHc8IxuguFVIZMNt3bi6YuC/t9r7BGD8bOOpSgM= github.com/Kong/go-diff v1.2.2/go.mod h1:nlvdwVZQk3Rm+tbI0cDmKFrOjghtcZTrZBp+UruvvA8= github.com/Kong/gojsondiff v1.3.2 h1:qIOVq2mUXt+NXy8Be5gRUee9TP3Ve0MbQSafg9bXKZE= github.com/Kong/gojsondiff v1.3.2/go.mod h1:DiIxtU59q4alK7ecP+7k56C5UjgOviJ5gQVR2esEhYw= github.com/Kong/yaml v1.0.0 h1:OWOxtLEamLYKZzcrfoH76imAwSi9FgSZapxg1Kh6IBA= github.com/Kong/yaml v1.0.0/go.mod h1:gVzJ3lyC0UdO7kZxmCpwn0Vj20y/02cFnDpHBirGrSQ= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= @@ -23,11 +29,17 @@ github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/ github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4= github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/adrg/strutil v0.3.0 h1:bi/HB2zQbDihC8lxvATDTDzkT4bG7PATtVnDYp5rvq4= github.com/adrg/strutil v0.3.0/go.mod h1:Jz0wzBVE6Uiy9wxo62YEqEY1Nwto3QlLl1Il5gkLKWU= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= +github.com/avast/retry-go/v4 v4.6.0 h1:K9xNA+KeB8HHc2aWFuLb25Offp+0iVRXEvFx8IinRJA= +github.com/avast/retry-go/v4 v4.6.0/go.mod h1:gvWlPhBVsvBbLkVGDg/KwvBv0bEkCOLRRSHKIr2PyOE= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= @@ -36,26 +48,42 @@ github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMU github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= +github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/daveshanley/vacuum v0.9.15 h1:QeSHYhbcB7x4chhOTsdxlZNBdipbFthusQkzeISplT0= github.com/daveshanley/vacuum v0.9.15/go.mod h1:xTTqOXVYJcEtvRe9YD07rhb0eK4zG6MRRjrmMadP5Kg= +github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= +github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/docker/docker v26.1.4+incompatible h1:vuTpXDuoga+Z38m1OZHzl7NKisKWaWlhjQk7IDPSLsU= +github.com/docker/docker v26.1.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja v0.0.0-20240220182346-e401ed450204 h1:O7I1iuzEA7SG+dK8ocOBSlYAA9jBUmCYl/Qa7ey7JAM= github.com/dop251/goja v0.0.0-20240220182346-e401ed450204/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= @@ -68,23 +96,41 @@ github.com/dprotaso/go-yit v0.0.0-20240618133044-5a0af90af097 h1:f5nA5Ys8RXqFXtK github.com/dprotaso/go-yit v0.0.0-20240618133044-5a0af90af097/go.mod h1:FTAVyH6t+SlS97rv6EXRVuBDLkQqcIe/xQw9f4IFUI4= github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk= github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= +github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= +github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= +github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw= +github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= @@ -101,22 +147,31 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -131,16 +186,25 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gosimple/slug v1.14.0 h1:RtTL/71mJNDfpUbCOmnf/XFkzKRtD6wL6Uy+3akm4Es= github.com/gosimple/slug v1.14.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= @@ -191,6 +255,8 @@ github.com/kong/go-slugify v1.0.0 h1:vCFAyf2sdoSlBtLcrmDWUFn0ohlpKiKvQfXZkO5vSKY github.com/kong/go-slugify v1.0.0/go.mod h1:dbR2h3J2QKXQ1k0aww6cN7o4cIcwlWflr6RKRdcoaiw= github.com/kong/kubernetes-ingress-controller/v3 v3.2.4 h1:5QKzRMHWAePwa9HGj3xtvgridzeG72xd3BftDP+PcjU= github.com/kong/kubernetes-ingress-controller/v3 v3.2.4/go.mod h1:kbbsyyNw/2HdURecav7iFcjAOtNXoUP5CfYFYJgiJq4= +github.com/kong/kubernetes-testing-framework v0.47.1 h1:BE2mQLC0Zj/NC5Y8B1Nm5VZymmrdVfu7cfwVKSobWtg= +github.com/kong/kubernetes-testing-framework v0.47.1/go.mod h1:9E53E99mlIGLgBU7R529X7IAUnVY8H1IqZecvGLZeco= github.com/kong/semver/v4 v4.0.1 h1:DIcNR8W3gfx0KabFBADPalxxsp+q/5COwIFkkhrFQ2Y= github.com/kong/semver/v4 v4.0.1/go.mod h1:LImQ0oT15pJvSns/hs2laLca2zcYoHu5EsSNY0J6/QA= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -202,6 +268,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a h1:N9zuLhTvBSRt0gWSiJswwQ2HqDmtX/ZCDJURnKUt1Ik= @@ -220,15 +288,31 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= +github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mozillazg/go-unidecode v0.2.0 h1:vFGEzAH9KSwyWmXCOblazEWDh7fOkpmy/Z4ArmamSUc= github.com/mozillazg/go-unidecode v0.2.0/go.mod h1:zB48+/Z5toiRolOZy9ksLryJ976VIwmDmpQ2quyt1aA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -248,19 +332,28 @@ github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAl github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/pb33f/doctor v0.0.6 h1:su/mIujJy0rB8KsdpTl7cC4RAHZdTyB7V5SjXu+xVWE= github.com/pb33f/doctor v0.0.6/go.mod h1:yBs5hFHAoo/eeFvKN9sWwmHmgEPJ2SaotYOJc05GdMU= github.com/pb33f/libopenapi v0.16.13 h1:uR/W3Rit/yxRWG5DWal26PdEnEq4mu/3cYjbkK6LHm0= github.com/pb33f/libopenapi v0.16.13/go.mod h1:8/lZGTZmxybpTPOggS6LefdrYvsQ5kbirD364TceyQo= github.com/pb33f/libopenapi-validator v0.0.49 h1:oJ4Jukib2pCvW0ccdVVyIyK/s5LCNvAuNt1U+PnGgEs= github.com/pb33f/libopenapi-validator v0.0.49/go.mod h1:kU1JYyXIRlpmsWx3NkL+drNNttLADMgdaNzJgXDhec0= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig= github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= @@ -276,6 +369,7 @@ github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= @@ -286,12 +380,16 @@ github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPO github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sethvargo/go-password v0.3.0 h1:OLFHZ91Z7NiNP3dnaPxLxCDXlb6TBuxFzMvv6bu+Ptw= +github.com/sethvargo/go-password v0.3.0/go.mod h1:p6we8DZ0eyYXof9pon7Cqrw98N4KTaYiadDml1dUEEw= github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= @@ -302,13 +400,15 @@ github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= -github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/ssgelm/cookiejarparser v1.0.1 h1:cRdXauUbOTFzTPJFaeiWbHnQ+tRGlpKKzvIK9PUekE4= github.com/ssgelm/cookiejarparser v1.0.1/go.mod h1:DUfC0mpjIzlDN7DzKjXpHj0qMI5m9VrZuz3wSlI+OEI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -345,6 +445,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= +github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= @@ -359,21 +461,53 @@ github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 h1:FyjCyI9jVEfqhUh2MoSkmolPjfh5fp2hnV0b0irxH4Q= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28 h1:zLxFnORHDFTSkJPawMU7LzsuGQJ4MUFS653jJHpORow= +go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28/go.mod h1:TQvodOM+hJTioNQJilmLXu08JNb8i+ccq418+KWu1/Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -387,7 +521,11 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -395,6 +533,7 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -412,11 +551,13 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -429,6 +570,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= @@ -441,7 +583,13 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -454,12 +602,30 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= @@ -470,6 +636,8 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= @@ -488,20 +656,32 @@ gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo= k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE= k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc= k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/cli-runtime v0.30.1 h1:kSBBpfrJGS6lllc24KeniI9JN7ckOOJKnmFYH1RpTOw= +k8s.io/cli-runtime v0.30.1/go.mod h1:zhHgbqI4J00pxb6gM3gJPVf2ysDjhQmQtnTxnMScab8= +k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= +k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= k8s.io/code-generator v0.31.0 h1:w607nrMi1KeDKB3/F/J4lIoOgAwc+gV9ZKew4XRfMp8= k8s.io/code-generator v0.31.0/go.mod h1:84y4w3es8rOJOUUP1rLsIiGlO1JuEaPFXQPA9e/K6U0= +k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs= +k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo= k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 h1:NGrVE502P0s0/1hudf8zjgwki1X/TByhmAoILTarmzo= k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f h1:0LQagt0gDpKqvIkAMPaRGcXawNMouPECM1+F9BVxEaM= k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f/go.mod h1:S9tOR0FxgyusSNR+MboCuiDpVWkAifZvaYI1Q2ubgro= +k8s.io/kubectl v0.30.1 h1:sHFIRI3oP0FFZmBAVEE8ErjnTyXDPkBcvO88mH9RjuY= +k8s.io/kubectl v0.30.1/go.mod h1:7j+L0Cc38RYEcx+WH3y44jRBe1Q1jxdGPKkX0h4iDq0= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= @@ -510,6 +690,12 @@ sigs.k8s.io/gateway-api v1.1.0 h1:DsLDXCi6jR+Xz8/xd0Z1PYl2Pn0TyaFMOPPZIj4inDM= sigs.k8s.io/gateway-api v1.1.0/go.mod h1:ZH4lHrL2sDi0FHZ9jjneb8kKnGzFWyrTya35sWUTrRs= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kind v0.23.0 h1:8fyDGWbWTeCcCTwA04v4Nfr45KKxbSPH1WO9K+jVrBg= +sigs.k8s.io/kind v0.23.0/go.mod h1:ZQ1iZuJLh3T+O8fzhdi3VWcFTzsdXtNv2ppsHc8JQ7s= +sigs.k8s.io/kustomize/api v0.17.2 h1:E7/Fjk7V5fboiuijoZHgs4aHuexi5Y2loXlVOAVAG5g= +sigs.k8s.io/kustomize/api v0.17.2/go.mod h1:UWTz9Ct+MvoeQsHcJ5e+vziRRkwimm3HytpZgIYqye0= +sigs.k8s.io/kustomize/kyaml v0.17.1 h1:TnxYQxFXzbmNG6gOINgGWQt09GghzgTP6mIurOgrLCQ= +sigs.k8s.io/kustomize/kyaml v0.17.1/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= diff --git a/kong2kic/builder_v2_gw_api.go b/kong2kic/builder_v2_gw_api.go index 74b9a3db7..a30d4e21f 100644 --- a/kong2kic/builder_v2_gw_api.go +++ b/kong2kic/builder_v2_gw_api.go @@ -24,7 +24,7 @@ func (b *KICv2GatewayAPIBuilder) buildServices(content *file.Content) { } func (b *KICv2GatewayAPIBuilder) buildRoutes(content *file.Content) { - err := populateKICIngressesWithGatewayAPI(content, b.kicContent) + err := populateKICIngressesWithAnnotations(content, b.kicContent) if err != nil { log.Fatal(err) } diff --git a/kong2kic/builder_v3_gw_api.go b/kong2kic/builder_v3_gw_api.go index 4f1b6820c..81f62b8d7 100644 --- a/kong2kic/builder_v3_gw_api.go +++ b/kong2kic/builder_v3_gw_api.go @@ -24,7 +24,7 @@ func (b *KICv3GatewayAPIBuider) buildServices(content *file.Content) { } func (b *KICv3GatewayAPIBuider) buildRoutes(content *file.Content) { - err := populateKICIngressesWithGatewayAPI(content, b.kicContent) + err := populateKICIngressesWithAnnotations(content, b.kicContent) if err != nil { log.Fatal(err) } diff --git a/kong2kic/ca_certificate.go b/kong2kic/ca_certificate.go index a9a65a075..7cd4e92a2 100644 --- a/kong2kic/ca_certificate.go +++ b/kong2kic/ca_certificate.go @@ -3,6 +3,8 @@ package kong2kic import ( "crypto/sha256" "fmt" + "log" + "strings" "github.com/kong/go-database-reconciler/pkg/file" k8scorev1 "k8s.io/api/core/v1" @@ -22,11 +24,28 @@ func populateKICCACertificate(content *file.Content, file *KICContent) { secret.ObjectMeta.Name = calculateSlug(secretName) secret.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} secret.StringData = make(map[string]string) - secret.StringData["ca.crt"] = *caCert.Cert + if caCert.Cert != nil { + secret.StringData["ca.crt"] = *caCert.Cert + } else { + log.Println("CA Certificate is empty. This is not recommended." + + "Please, provide a certificate for the CA before generating Kong Ingress Controller manifests.") + continue + } if caCert.CertDigest != nil { secret.StringData["ca.digest"] = *caCert.CertDigest } + // add konghq.com/tags annotation if cacert.Tags is not nil + if caCert.Tags != nil { + var tags []string + for _, tag := range caCert.Tags { + if tag != nil { + tags = append(tags, *tag) + } + } + secret.ObjectMeta.Annotations["konghq.com/tags"] = strings.Join(tags, ",") + } + file.Secrets = append(file.Secrets, secret) } } diff --git a/kong2kic/certificate.go b/kong2kic/certificate.go index 6d409b37d..48c4e9daf 100644 --- a/kong2kic/certificate.go +++ b/kong2kic/certificate.go @@ -3,6 +3,8 @@ package kong2kic import ( "crypto/sha256" "fmt" + "log" + "strings" "github.com/kong/go-database-reconciler/pkg/file" k8scorev1 "k8s.io/api/core/v1" @@ -22,10 +24,27 @@ func populateKICCertificates(content *file.Content, file *KICContent) { secret.ObjectMeta.Name = calculateSlug(secretName) secret.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} secret.StringData = make(map[string]string) - secret.StringData["tls.crt"] = *cert.Cert - secret.StringData["tls.key"] = *cert.Key + if cert.Cert != nil && cert.Key != nil { + secret.StringData["tls.crt"] = *cert.Cert + secret.StringData["tls.key"] = *cert.Key + } else { + log.Println("Certificate or Key is empty. This is not recommended." + + "Please, provide a certificate and key before generating Kong Ingress Controller manifests.") + continue + } // what to do with SNIs? + // add konghq.com/tags annotation if cert.Tags is not nil + if cert.Tags != nil { + var tags []string + for _, tag := range cert.Tags { + if tag != nil { + tags = append(tags, *tag) + } + } + secret.ObjectMeta.Annotations["konghq.com/tags"] = strings.Join(tags, ",") + } + file.Secrets = append(file.Secrets, secret) } } diff --git a/kong2kic/consumer.go b/kong2kic/consumer.go index a23a4f7c1..d0b30e203 100644 --- a/kong2kic/consumer.go +++ b/kong2kic/consumer.go @@ -1,31 +1,40 @@ package kong2kic import ( - "encoding/json" "log" - "strconv" "github.com/kong/go-database-reconciler/pkg/file" kicv1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1" - k8scorev1 "k8s.io/api/core/v1" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// Function to populate KIC Consumers and their credentials func populateKICConsumers(content *file.Content, file *KICContent) error { - // Iterate Kong Consumers and copy them into KongConsumer - for i := range content.Consumers { - consumer := content.Consumers[i] - - var kongConsumer kicv1.KongConsumer - kongConsumer.APIVersion = KICAPIVersion - kongConsumer.Kind = "KongConsumer" - kongConsumer.ObjectMeta.Name = calculateSlug(*consumer.Username) - kongConsumer.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} - kongConsumer.Username = *consumer.Username + for _, consumer := range content.Consumers { + if consumer.Username == nil { + log.Println("Consumer username is empty. Please provide a username for the consumer.") + continue + } + username := *consumer.Username + kongConsumer := kicv1.KongConsumer{ + TypeMeta: metav1.TypeMeta{ + APIVersion: KICAPIVersion, + Kind: "KongConsumer", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: calculateSlug(username), + Annotations: map[string]string{IngressClass: ClassName}, + }, + Username: username, + } if consumer.CustomID != nil { kongConsumer.CustomID = *consumer.CustomID } + // Add tags to annotations + addTagsToAnnotations(consumer.Tags, kongConsumer.ObjectMeta.Annotations) + + // Populate credentials populateKICKeyAuthSecrets(&consumer, &kongConsumer, file) populateKICHMACSecrets(&consumer, &kongConsumer, file) populateKICJWTAuthSecrets(&consumer, &kongConsumer, file) @@ -34,38 +43,17 @@ func populateKICConsumers(content *file.Content, file *KICContent) error { populateKICACLGroupSecrets(&consumer, &kongConsumer, file) populateKICMTLSAuthSecrets(&consumer, &kongConsumer, file) - // for each consumer.plugin, create a KongPlugin and a plugin annotation in the kongConsumer - // to link the plugin + // Handle plugins associated with the consumer for _, plugin := range consumer.Plugins { - var kongPlugin kicv1.KongPlugin - kongPlugin.APIVersion = KICAPIVersion - kongPlugin.Kind = KongPluginKind - kongPlugin.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} - if plugin.Name != nil { - kongPlugin.PluginName = *plugin.Name - kongPlugin.ObjectMeta.Name = calculateSlug(*consumer.Username + "-" + *plugin.Name) - } else { - log.Println("Plugin name is empty. This is not recommended." + - "Please, provide a name for the plugin before generating Kong Ingress Controller manifests.") - continue - } - - // transform the plugin config from map[string]interface{} to apiextensionsv1.JSON - var configJSON apiextensionsv1.JSON - var err error - configJSON.Raw, err = json.Marshal(plugin.Config) + kongPlugin, err := createKongPlugin(plugin, username) if err != nil { return err } - kongPlugin.Config = configJSON - file.KongPlugins = append(file.KongPlugins, kongPlugin) - - if kongConsumer.ObjectMeta.Annotations["konghq.com/plugins"] == "" { - kongConsumer.ObjectMeta.Annotations["konghq.com/plugins"] = kongPlugin.ObjectMeta.Name - } else { - annotations := kongConsumer.ObjectMeta.Annotations["konghq.com/plugins"] + "," + kongPlugin.ObjectMeta.Name - kongConsumer.ObjectMeta.Annotations["konghq.com/plugins"] = annotations + if kongPlugin == nil { + continue } + file.KongPlugins = append(file.KongPlugins, *kongPlugin) + addPluginToAnnotations(kongPlugin.ObjectMeta.Name, kongConsumer.ObjectMeta.Annotations) } file.KongConsumers = append(file.KongConsumers, kongConsumer) @@ -73,258 +61,3 @@ func populateKICConsumers(content *file.Content, file *KICContent) error { return nil } - -func populateKICMTLSAuthSecrets(consumer *file.FConsumer, kongConsumer *kicv1.KongConsumer, file *KICContent) { - // iterate consumer.MTLSAuths and copy them into k8scorev1.Secret, then add them to kicContent.Secrets - for _, mtlsAuth := range consumer.MTLSAuths { - var secret k8scorev1.Secret - secretName := "mtls-auth-" + *consumer.Username - secret.TypeMeta.APIVersion = "v1" - secret.TypeMeta.Kind = SecretKind - secret.Type = "Opaque" - secret.ObjectMeta.Name = calculateSlug(secretName) - secret.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} - secret.StringData = make(map[string]string) - if targetKICVersionAPI == KICV3GATEWAY || targetKICVersionAPI == KICV3INGRESS { - // for KIC v3, use the konghq.com/credential label to identify the credential type - secret.ObjectMeta.Labels = map[string]string{"konghq.com/credential": "mtls-auth"} - } else { - // for KIC v2, use the kongCredType field to identify the credential type - secret.StringData["kongCredType"] = "mtls-auth" - } - - if mtlsAuth.SubjectName != nil { - secret.StringData["subject_name"] = *mtlsAuth.SubjectName - } - - if mtlsAuth.ID != nil { - secret.StringData["id"] = *mtlsAuth.ID - } - - if mtlsAuth.CACertificate != nil && mtlsAuth.CACertificate.Cert != nil { - secret.StringData["ca_certificate"] = *mtlsAuth.CACertificate.Cert - } - - // add the secret name to the kongConsumer.credentials - kongConsumer.Credentials = append(kongConsumer.Credentials, secretName) - - file.Secrets = append(file.Secrets, secret) - } -} - -func populateKICACLGroupSecrets(consumer *file.FConsumer, kongConsumer *kicv1.KongConsumer, file *KICContent) { - // iterate consumer.ACLGroups and copy them into k8scorev1.Secret, then add them to kicContent.Secrets - for _, aclGroup := range consumer.ACLGroups { - var secret k8scorev1.Secret - secretName := "acl-group-" + *consumer.Username - secret.TypeMeta.APIVersion = "v1" - secret.TypeMeta.Kind = SecretKind - secret.ObjectMeta.Name = calculateSlug(secretName) - secret.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} - secret.StringData = make(map[string]string) - - if targetKICVersionAPI == KICV3GATEWAY || targetKICVersionAPI == KICV3INGRESS { - // for KIC v3, use the konghq.com/credential label to identify the credential type - secret.ObjectMeta.Labels = map[string]string{"konghq.com/credential": "acl"} - } else { - // for KIC v2, use the kongCredType field to identify the credential type - secret.StringData["kongCredType"] = "acl" - } - - if aclGroup.Group != nil { - secret.StringData["group"] = *aclGroup.Group - } - - // add the secret name to the kongConsumer.credentials - kongConsumer.Credentials = append(kongConsumer.Credentials, secretName) - - file.Secrets = append(file.Secrets, secret) - } -} - -func populateKICOAuth2CredSecrets(consumer *file.FConsumer, kongConsumer *kicv1.KongConsumer, file *KICContent) { - // iterate consumer.OAuth2Creds and copy them into k8scorev1.Secret, then add them to kicContent.Secrets - for _, oauth2Cred := range consumer.Oauth2Creds { - var secret k8scorev1.Secret - secretName := "oauth2cred-" + *consumer.Username - secret.TypeMeta.APIVersion = "v1" - secret.TypeMeta.Kind = SecretKind - secret.ObjectMeta.Name = calculateSlug(secretName) - secret.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} - secret.StringData = make(map[string]string) - - if targetKICVersionAPI == KICV3GATEWAY || targetKICVersionAPI == KICV3INGRESS { - // for KIC v3, use the konghq.com/credential label to identify the credential type - secret.ObjectMeta.Labels = map[string]string{"konghq.com/credential": "oauth2"} - } else { - // for KIC v2, use the kongCredType field to identify the credential type - secret.StringData["kongCredType"] = "oauth2" - } - - if oauth2Cred.Name != nil { - secret.StringData["name"] = *oauth2Cred.Name - } - - if oauth2Cred.ClientID != nil { - secret.StringData["client_id"] = *oauth2Cred.ClientID - } - - if oauth2Cred.ClientSecret != nil { - secret.StringData["client_secret"] = *oauth2Cred.ClientSecret - } - - if oauth2Cred.ClientType != nil { - secret.StringData["client_type"] = *oauth2Cred.ClientType - } - - if oauth2Cred.HashSecret != nil { - secret.StringData["hash_secret"] = strconv.FormatBool(*oauth2Cred.HashSecret) - } - - // add the secret name to the kongConsumer.credentials - kongConsumer.Credentials = append(kongConsumer.Credentials, secretName) - - file.Secrets = append(file.Secrets, secret) - } -} - -func populateKICBasicAuthSecrets(consumer *file.FConsumer, kongConsumer *kicv1.KongConsumer, file *KICContent) { - // iterate consumer.BasicAuths and copy them into k8scorev1.Secret, then add them to kicContent.Secrets - for _, basicAuth := range consumer.BasicAuths { - var secret k8scorev1.Secret - secretName := "basic-auth-" + *consumer.Username - secret.TypeMeta.APIVersion = "v1" - secret.TypeMeta.Kind = SecretKind - secret.ObjectMeta.Name = calculateSlug(secretName) - secret.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} - secret.StringData = make(map[string]string) - - if targetKICVersionAPI == KICV3GATEWAY || targetKICVersionAPI == KICV3INGRESS { - // for KIC v3, use the konghq.com/credential label to identify the credential type - secret.ObjectMeta.Labels = map[string]string{"konghq.com/credential": "basic-auth"} - } else { - // for KIC v2, use the kongCredType field to identify the credential type - secret.StringData["kongCredType"] = "basic-auth" - } - - if basicAuth.Username != nil { - secret.StringData["username"] = *basicAuth.Username - } - if basicAuth.Password != nil { - secret.StringData["password"] = *basicAuth.Password - } - - // add the secret name to the kongConsumer.credentials - kongConsumer.Credentials = append(kongConsumer.Credentials, secretName) - - file.Secrets = append(file.Secrets, secret) - } -} - -func populateKICJWTAuthSecrets(consumer *file.FConsumer, kongConsumer *kicv1.KongConsumer, file *KICContent) { - // iterate consumer.JWTAuths and copy them into k8scorev1.Secret, then add them to kicContent.Secrets - for _, jwtAuth := range consumer.JWTAuths { - var secret k8scorev1.Secret - secretName := "jwt-auth-" + *consumer.Username - secret.TypeMeta.APIVersion = "v1" - secret.TypeMeta.Kind = SecretKind - secret.ObjectMeta.Name = calculateSlug(secretName) - secret.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} - secret.StringData = make(map[string]string) - - if targetKICVersionAPI == KICV3GATEWAY || targetKICVersionAPI == KICV3INGRESS { - // for KIC v3, use the konghq.com/credential label to identify the credential type - secret.ObjectMeta.Labels = map[string]string{"konghq.com/credential": "jwt"} - } else { - // for KIC v2, use the kongCredType field to identify the credential type - secret.StringData["kongCredType"] = "jwt" - } - - // only do the following assignments if not null - if jwtAuth.Key != nil { - secret.StringData["key"] = *jwtAuth.Key - } - - if jwtAuth.Algorithm != nil { - secret.StringData["algorithm"] = *jwtAuth.Algorithm - } - - if jwtAuth.RSAPublicKey != nil { - secret.StringData["rsa_public_key"] = *jwtAuth.RSAPublicKey - } - - if jwtAuth.Secret != nil { - secret.StringData["secret"] = *jwtAuth.Secret - } - - // add the secret name to the kongConsumer.credentials - kongConsumer.Credentials = append(kongConsumer.Credentials, secretName) - - file.Secrets = append(file.Secrets, secret) - } -} - -func populateKICHMACSecrets(consumer *file.FConsumer, kongConsumer *kicv1.KongConsumer, file *KICContent) { - // iterate consumer.HMACAuths and copy them into k8scorev1.Secret, then add them to kicContent.Secrets - for _, hmacAuth := range consumer.HMACAuths { - var secret k8scorev1.Secret - secretName := "hmac-auth-" + *consumer.Username - secret.TypeMeta.APIVersion = "v1" - secret.TypeMeta.Kind = SecretKind - secret.ObjectMeta.Name = calculateSlug(secretName) - secret.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} - secret.StringData = make(map[string]string) - - if targetKICVersionAPI == KICV3GATEWAY || targetKICVersionAPI == KICV3INGRESS { - // for KIC v3, use the konghq.com/credential label to identify the credential type - secret.ObjectMeta.Labels = map[string]string{"konghq.com/credential": "hmac-auth"} - } else { - // for KIC v2, use the kongCredType field to identify the credential type - secret.StringData["kongCredType"] = "hmac-auth" - } - - if hmacAuth.Username != nil { - secret.StringData["username"] = *hmacAuth.Username - } - - if hmacAuth.Secret != nil { - secret.StringData["secret"] = *hmacAuth.Secret - } - - // add the secret name to the kongConsumer.credentials - kongConsumer.Credentials = append(kongConsumer.Credentials, secretName) - - file.Secrets = append(file.Secrets, secret) - } -} - -func populateKICKeyAuthSecrets(consumer *file.FConsumer, kongConsumer *kicv1.KongConsumer, file *KICContent) { - // iterate consumer.KeyAuths and copy them into k8scorev1.Secret, then add them to kicContent.Secrets - // add the secret name to the kongConsumer.credentials - for _, keyAuth := range consumer.KeyAuths { - var secret k8scorev1.Secret - secretName := "key-auth-" + *consumer.Username - secret.TypeMeta.APIVersion = "v1" - secret.TypeMeta.Kind = SecretKind - secret.ObjectMeta.Name = calculateSlug(secretName) - secret.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} - secret.StringData = make(map[string]string) - - if targetKICVersionAPI == KICV3GATEWAY || targetKICVersionAPI == KICV3INGRESS { - // for KIC v3, use the konghq.com/credential label to identify the credential type - secret.ObjectMeta.Labels = map[string]string{"konghq.com/credential": "key-auth"} - } else { - // for KIC v2, use the kongCredType field to identify the credential type - secret.StringData["kongCredType"] = "key-auth" - } - - if keyAuth.Key != nil { - secret.StringData["key"] = *keyAuth.Key - } - - kongConsumer.Credentials = append(kongConsumer.Credentials, secretName) - - file.Secrets = append(file.Secrets, secret) - - } -} diff --git a/kong2kic/consumer_credentials.go b/kong2kic/consumer_credentials.go new file mode 100644 index 000000000..55760f019 --- /dev/null +++ b/kong2kic/consumer_credentials.go @@ -0,0 +1,137 @@ +package kong2kic + +import ( + "strconv" + + "github.com/kong/go-database-reconciler/pkg/file" + kicv1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1" + k8scorev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Helper function to create credential secrets +func createCredentialSecret(consumerUsername, credentialType string, dataFields map[string]*string) k8scorev1.Secret { + secretName := credentialType + "-" + consumerUsername + stringData := make(map[string]string) + labels := map[string]string{} + if targetKICVersionAPI == KICV3GATEWAY || targetKICVersionAPI == KICV3INGRESS { + labels["konghq.com/credential"] = credentialType + } else { + stringData["kongCredType"] = credentialType + } + + // Add the data fields to stringData + for key, value := range dataFields { + if value != nil { + stringData[key] = *value + } + } + + return k8scorev1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: SecretKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: calculateSlug(secretName), + Annotations: map[string]string{IngressClass: ClassName}, + Labels: labels, + }, + Type: "Opaque", + StringData: stringData, + } +} + +// Functions to populate different credential types +func populateKICKeyAuthSecrets(consumer *file.FConsumer, kongConsumer *kicv1.KongConsumer, file *KICContent) { + for _, keyAuth := range consumer.KeyAuths { + dataFields := map[string]*string{ + "key": keyAuth.Key, + } + secret := createCredentialSecret(*consumer.Username, "key-auth", dataFields) + kongConsumer.Credentials = append(kongConsumer.Credentials, secret.ObjectMeta.Name) + file.Secrets = append(file.Secrets, secret) + } +} + +func populateKICHMACSecrets(consumer *file.FConsumer, kongConsumer *kicv1.KongConsumer, file *KICContent) { + for _, hmacAuth := range consumer.HMACAuths { + dataFields := map[string]*string{ + "username": hmacAuth.Username, + "secret": hmacAuth.Secret, + } + secret := createCredentialSecret(*consumer.Username, "hmac-auth", dataFields) + kongConsumer.Credentials = append(kongConsumer.Credentials, secret.ObjectMeta.Name) + file.Secrets = append(file.Secrets, secret) + } +} + +func populateKICJWTAuthSecrets(consumer *file.FConsumer, kongConsumer *kicv1.KongConsumer, file *KICContent) { + for _, jwtAuth := range consumer.JWTAuths { + dataFields := map[string]*string{ + "key": jwtAuth.Key, + "algorithm": jwtAuth.Algorithm, + "rsa_public_key": jwtAuth.RSAPublicKey, + "secret": jwtAuth.Secret, + } + secret := createCredentialSecret(*consumer.Username, "jwt", dataFields) + kongConsumer.Credentials = append(kongConsumer.Credentials, secret.ObjectMeta.Name) + file.Secrets = append(file.Secrets, secret) + } +} + +func populateKICBasicAuthSecrets(consumer *file.FConsumer, kongConsumer *kicv1.KongConsumer, file *KICContent) { + for _, basicAuth := range consumer.BasicAuths { + dataFields := map[string]*string{ + "username": basicAuth.Username, + "password": basicAuth.Password, + } + secret := createCredentialSecret(*consumer.Username, "basic-auth", dataFields) + kongConsumer.Credentials = append(kongConsumer.Credentials, secret.ObjectMeta.Name) + file.Secrets = append(file.Secrets, secret) + } +} + +func populateKICOAuth2CredSecrets(consumer *file.FConsumer, kongConsumer *kicv1.KongConsumer, file *KICContent) { + for _, oauth2Cred := range consumer.Oauth2Creds { + dataFields := map[string]*string{ + "name": oauth2Cred.Name, + "client_id": oauth2Cred.ClientID, + "client_secret": oauth2Cred.ClientSecret, + "client_type": oauth2Cred.ClientType, + } + if oauth2Cred.HashSecret != nil { + hashSecretStr := strconv.FormatBool(*oauth2Cred.HashSecret) + dataFields["hash_secret"] = &hashSecretStr + } + secret := createCredentialSecret(*consumer.Username, "oauth2", dataFields) + kongConsumer.Credentials = append(kongConsumer.Credentials, secret.ObjectMeta.Name) + file.Secrets = append(file.Secrets, secret) + } +} + +func populateKICACLGroupSecrets(consumer *file.FConsumer, kongConsumer *kicv1.KongConsumer, file *KICContent) { + for _, aclGroup := range consumer.ACLGroups { + dataFields := map[string]*string{ + "group": aclGroup.Group, + } + secret := createCredentialSecret(*consumer.Username, "acl", dataFields) + kongConsumer.Credentials = append(kongConsumer.Credentials, secret.ObjectMeta.Name) + file.Secrets = append(file.Secrets, secret) + } +} + +func populateKICMTLSAuthSecrets(consumer *file.FConsumer, kongConsumer *kicv1.KongConsumer, file *KICContent) { + for _, mtlsAuth := range consumer.MTLSAuths { + dataFields := map[string]*string{ + "subject_name": mtlsAuth.SubjectName, + "id": mtlsAuth.ID, + } + if mtlsAuth.CACertificate != nil && mtlsAuth.CACertificate.Cert != nil { + dataFields["ca_certificate"] = mtlsAuth.CACertificate.Cert + } + secret := createCredentialSecret(*consumer.Username, "mtls-auth", dataFields) + kongConsumer.Credentials = append(kongConsumer.Credentials, secret.ObjectMeta.Name) + file.Secrets = append(file.Secrets, secret) + } +} diff --git a/kong2kic/consumer_group.go b/kong2kic/consumer_group.go index a252a1861..a39f30666 100644 --- a/kong2kic/consumer_group.go +++ b/kong2kic/consumer_group.go @@ -5,76 +5,94 @@ import ( "log" "github.com/kong/go-database-reconciler/pkg/file" + "github.com/kong/go-kong/kong" kicv1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1" kicv1beta1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1beta1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// Helper function to populate consumer group plugins +func createConsumerGroupKongPlugin(plugin *kong.ConsumerGroupPlugin, ownerName string) (*kicv1.KongPlugin, error) { + if plugin.Name == nil { + log.Println("Plugin name is empty. Please provide a name for the plugin.") + return nil, nil + } + pluginName := *plugin.Name + kongPlugin := &kicv1.KongPlugin{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "configuration.konghq.com/v1", + Kind: "KongPlugin", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: calculateSlug(ownerName + "-" + pluginName), + Annotations: map[string]string{IngressClass: ClassName}, + }, + PluginName: pluginName, + } + + // Transform the plugin config + configJSON, err := json.Marshal(plugin.Config) + if err != nil { + return nil, err + } + kongPlugin.Config = apiextensionsv1.JSON{ + Raw: configJSON, + } + + return kongPlugin, nil +} + func populateKICConsumerGroups(content *file.Content, kicContent *KICContent) error { - // iterate over the consumer groups and create a KongConsumerGroup for each one for _, consumerGroup := range content.ConsumerGroups { - var kongConsumerGroup kicv1beta1.KongConsumerGroup - kongConsumerGroup.APIVersion = "configuration.konghq.com/v1beta1" - kongConsumerGroup.Kind = "KongConsumerGroup" - if consumerGroup.Name != nil { - kongConsumerGroup.ObjectMeta.Name = calculateSlug(*consumerGroup.Name) - } else { - log.Println("Consumer group name is empty. This is not recommended." + - "Please, provide a name for the consumer group before generating Kong Ingress Controller manifests.") + if consumerGroup.Name == nil { + log.Println("Consumer group name is empty. Please provide a name for the consumer group.") continue } - kongConsumerGroup.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} - kongConsumerGroup.Name = *consumerGroup.Name + groupName := *consumerGroup.Name + + kongConsumerGroup := kicv1beta1.KongConsumerGroup{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "configuration.konghq.com/v1beta1", + Kind: "KongConsumerGroup", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: calculateSlug(groupName), + Annotations: map[string]string{IngressClass: ClassName}, + }, + } + + // Add tags to annotations + addTagsToAnnotations(consumerGroup.Tags, kongConsumerGroup.ObjectMeta.Annotations) - // Iterate over the consumers in consumerGroup and - // find the KongConsumer with the same username in kicContent.KongConsumers - // and add it to the KongConsumerGroup + // Update the ConsumerGroups field of the KongConsumers for _, consumer := range consumerGroup.Consumers { + if consumer.Username == nil { + log.Println("Consumer username is empty. Please provide a username for the consumer.") + continue + } + username := *consumer.Username for idx := range kicContent.KongConsumers { - if kicContent.KongConsumers[idx].Username == *consumer.Username { - if kicContent.KongConsumers[idx].ConsumerGroups == nil { - kicContent.KongConsumers[idx].ConsumerGroups = make([]string, 0) - } - consumerGroups := append(kicContent.KongConsumers[idx].ConsumerGroups, *consumerGroup.Name) - kicContent.KongConsumers[idx].ConsumerGroups = consumerGroups + if kicContent.KongConsumers[idx].Username == username { + kicContent.KongConsumers[idx].ConsumerGroups = append(kicContent.KongConsumers[idx].ConsumerGroups, groupName) } } } - // for each consumerGroup plugin, create a KongPlugin and a plugin annotation in the kongConsumerGroup - // to link the plugin. Consumer group plugins are "global plugins" with a consumer_group property - for _, plugin := range content.Plugins { - if plugin.ConsumerGroup.ID != nil && *plugin.ConsumerGroup.ID == *consumerGroup.Name { - var kongPlugin kicv1.KongPlugin - kongPlugin.APIVersion = KICAPIVersion - kongPlugin.Kind = KongPluginKind - kongPlugin.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} - if plugin.Name != nil { - kongPlugin.PluginName = *consumerGroup.Name + "-" + *plugin.Name - kongPlugin.ObjectMeta.Name = calculateSlug(*consumerGroup.Name + "-" + *plugin.Name) - } else { - log.Println("Plugin name is empty. This is not recommended." + - "Please, provide a name for the plugin before generating Kong Ingress Controller manifests.") - continue - } + // Handle plugins + for _, plugin := range consumerGroup.Plugins { + kongPlugin, err := createConsumerGroupKongPlugin(plugin, groupName) + if err != nil { + return err + } + if kongPlugin == nil { + continue + } - // transform the plugin config from map[string]interface{} to apiextensionsv1.JSON - var configJSON apiextensionsv1.JSON - var err error - configJSON.Raw, err = json.Marshal(plugin.Config) - if err != nil { - return err - } - kongPlugin.Config = configJSON - kicContent.KongPlugins = append(kicContent.KongPlugins, kongPlugin) + kicContent.KongPlugins = append(kicContent.KongPlugins, *kongPlugin) - if kongConsumerGroup.ObjectMeta.Annotations["konghq.com/plugins"] == "" { - kongConsumerGroup.ObjectMeta.Annotations["konghq.com/plugins"] = kongPlugin.ObjectMeta.Name - } else { - annotations := kongConsumerGroup.ObjectMeta.Annotations["konghq.com/plugins"] + "," + kongPlugin.ObjectMeta.Name - kongConsumerGroup.ObjectMeta.Annotations["konghq.com/plugins"] = annotations - } - } + // Add plugin to kongConsumerGroup annotations + addPluginToAnnotations(kongPlugin.ObjectMeta.Name, kongConsumerGroup.ObjectMeta.Annotations) } kicContent.KongConsumerGroups = append(kicContent.KongConsumerGroups, kongConsumerGroup) diff --git a/kong2kic/global_plugin.go b/kong2kic/global_plugin.go index 5c7b7e5cc..b5ab3fa39 100644 --- a/kong2kic/global_plugin.go +++ b/kong2kic/global_plugin.go @@ -3,8 +3,10 @@ package kong2kic import ( "encoding/json" "log" + "strings" "github.com/kong/go-database-reconciler/pkg/file" + "github.com/kong/go-kong/kong" kicv1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" ) @@ -19,19 +21,53 @@ func populateKICKongClusterPlugins(content *file.Content, file *KICContent) erro if plugin.ConsumerGroup != nil { continue } - var kongPlugin kicv1.KongClusterPlugin - kongPlugin.APIVersion = KICAPIVersion - kongPlugin.Kind = "KongClusterPlugin" - kongPlugin.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} + var kongClusterPlugin kicv1.KongClusterPlugin + kongClusterPlugin.APIVersion = KICAPIVersion + kongClusterPlugin.Kind = "KongClusterPlugin" + kongClusterPlugin.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} if plugin.Name != nil { - kongPlugin.PluginName = *plugin.Name - kongPlugin.ObjectMeta.Name = calculateSlug(*plugin.Name) + kongClusterPlugin.PluginName = *plugin.Name + kongClusterPlugin.ObjectMeta.Name = calculateSlug(*plugin.Name) } else { log.Println("Global Plugin name is empty. This is not recommended." + "Please, provide a name for the plugin before generating Kong Ingress Controller manifests.") continue } + // populate enabled, runon, ordering and protocols + if plugin.Enabled != nil { + kongClusterPlugin.Disabled = !*plugin.Enabled + } + if plugin.RunOn != nil { + kongClusterPlugin.RunOn = *plugin.RunOn + } + if plugin.Ordering != nil { + kongClusterPlugin.Ordering = &kong.PluginOrdering{ + Before: plugin.Ordering.Before, + After: plugin.Ordering.After, + } + } + if plugin.Protocols != nil { + protocols := make([]string, len(plugin.Protocols)) + for i, protocol := range plugin.Protocols { + if protocol != nil { + protocols[i] = *protocol + } + } + kongClusterPlugin.Protocols = kicv1.StringsToKongProtocols(protocols) + } + + // add konghq.com/tags annotation if plugin.Tags is not nil + if plugin.Tags != nil { + var tags []string + for _, tag := range plugin.Tags { + if tag != nil { + tags = append(tags, *tag) + } + } + kongClusterPlugin.ObjectMeta.Annotations["konghq.com/tags"] = strings.Join(tags, ",") + } + // transform the plugin config from map[string]interface{} to apiextensionsv1.JSON var configJSON apiextensionsv1.JSON var err error @@ -39,8 +75,8 @@ func populateKICKongClusterPlugins(content *file.Content, file *KICContent) erro if err != nil { return err } - kongPlugin.Config = configJSON - file.KongClusterPlugins = append(file.KongClusterPlugins, kongPlugin) + kongClusterPlugin.Config = configJSON + file.KongClusterPlugins = append(file.KongClusterPlugins, kongClusterPlugin) } return nil } diff --git a/kong2kic/kong2kic_test.go b/kong2kic/kong2kic_test.go index fc5031a8f..a7ca821b6 100644 --- a/kong2kic/kong2kic_test.go +++ b/kong2kic/kong2kic_test.go @@ -1,40 +1,71 @@ package kong2kic import ( + "bytes" + "context" + "errors" + "io" + "net/http" "os" + "path/filepath" + "regexp" "strings" + "sync" "testing" + "time" "github.com/kong/go-database-reconciler/pkg/file" - "github.com/stretchr/testify/assert" + "github.com/kong/kubernetes-testing-framework/pkg/clusters/addons/kong" + "github.com/kong/kubernetes-testing-framework/pkg/clusters/addons/metallb" + environment "github.com/kong/kubernetes-testing-framework/pkg/environments" "github.com/stretchr/testify/require" + apiv1 "k8s.io/api/core/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/yaml" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" ) var baseLocation = "testdata/" -func fixJSONstream(input string) string { - // this is a stream of json files, must update to an actual json array - return "[" + strings.Replace(input, "}{", "},{", -1) + "]" +// Helper function to read and fix JSON stream +func readAndFixJSONStream(filename string) (string, error) { + content, err := os.ReadFile(filepath.Join(baseLocation, filename)) + if err != nil { + return "", err + } + // Update to an actual JSON array + fixedContent := "[" + strings.ReplaceAll(string(content), "}{", "},{") + "]" + return fixedContent, nil } +// Helper function to compare file content func compareFileContent(t *testing.T, expectedFilename string, actualContent []byte) { - expected, err := os.ReadFile(baseLocation + expectedFilename) - if err != nil { - assert.Fail(t, err.Error()) - } + expectedPath := filepath.Join(baseLocation, expectedFilename) + expectedContent, err := os.ReadFile(expectedPath) + require.NoError(t, err) - actualFilename := baseLocation + strings.Replace(expectedFilename, "-expected.", "-actual.", 1) - os.WriteFile(actualFilename, actualContent, 0o600) + // Write actual content to file for debugging + actualFilename := strings.Replace(expectedFilename, "-expected.", "-actual.", 1) + actualPath := filepath.Join(baseLocation, actualFilename) + err = os.WriteFile(actualPath, actualContent, 0o600) + require.NoError(t, err) if strings.HasSuffix(expectedFilename, ".json") { - // this is a stream of json files, must update to an actual json array - require.JSONEq(t, fixJSONstream(string(expected)), fixJSONstream(string(actualContent))) + expectedJSON, err := readAndFixJSONStream(expectedFilename) + require.NoError(t, err) + actualJSON := "[" + strings.ReplaceAll(string(actualContent), "}{", "},{") + "]" + require.JSONEq(t, expectedJSON, actualJSON) } else { - require.YAMLEq(t, string(expected), string(actualContent)) + require.YAMLEq(t, string(expectedContent), string(actualContent)) } } -func Test_convertKongGatewayToIngress(t *testing.T) { +func Test_convertKongGatewayToKIC(t *testing.T) { tests := []struct { name string inputFilename string @@ -43,81 +74,437 @@ func Test_convertKongGatewayToIngress(t *testing.T) { wantErr bool }{ { - name: "Kong to KIC: kic v3.x Gateway API, yaml", - inputFilename: "input.yaml", - outputFilename: "kicv3_gateway/output-expected.yaml", + // Service does not depend on v2 vs v3, or Gateway vs Ingress + name: "Kong to KIC: Service", + inputFilename: "service-input.yaml", + outputFilename: "service-output-expected.yaml", builderType: KICV3GATEWAY, wantErr: false, }, { - name: "Kong to KIC: kic v3.x Gateway API, json", - inputFilename: "input.yaml", - outputFilename: "kicv3_gateway/output-expected.json", + // Route to HTTPRoute, Gateway API and KIC v3. + // In KIC v3 apiVersion: gateway.networking.k8s.io/v1 + name: "Kong to KIC: Route API GW, KIC v3", + inputFilename: "route-input.yaml", + outputFilename: "route-gw-v3-output-expected.yaml", builderType: KICV3GATEWAY, wantErr: false, }, { - name: "Kong to KIC: kic v3.x Ingress API, yaml", - inputFilename: "input.yaml", - outputFilename: "kicv3_ingress/output-expected.yaml", - builderType: KICV3INGRESS, + // Route to HTTPRoute, Gateway API and KIC v2 + // In KIC v2 apiVersion: gateway.networking.k8s.io/v1beta1 + name: "Kong to KIC: Route API GW, KIC v2", + inputFilename: "route-input.yaml", + outputFilename: "route-gw-v2-output-expected.yaml", + builderType: KICV2GATEWAY, wantErr: false, }, { - name: "Kong to KIC: kic v3.x Ingress API, json", - inputFilename: "input.yaml", - outputFilename: "kicv3_ingress/output-expected.json", + // Route to Ingress, Ingress API. Output does not depend on KIC v2 vs v3 + name: "Kong to KIC: Route Ingress API", + inputFilename: "route-input.yaml", + outputFilename: "route-ingress-output-expected.yaml", builderType: KICV3INGRESS, wantErr: false, }, { - name: "Kong to KIC: kic v2.x Gateway API, yaml", - inputFilename: "input.yaml", - outputFilename: "kicv2_gateway/output-expected.yaml", + // Upstream to KongIngress for KIC v2 + name: "Kong to KIC: Upstream KIC v2", + inputFilename: "upstream-input.yaml", + outputFilename: "upstream-v2-output-expected.yaml", builderType: KICV2GATEWAY, wantErr: false, }, { - name: "Kong to KIC: kic v2.x Gateway API, json", - inputFilename: "input.yaml", - outputFilename: "kicv2_gateway/output-expected.json", + // Upstream to KongUpstreamPolicy for KIC v3 + name: "Kong to KIC: Upstream KIC v3", + inputFilename: "upstream-input.yaml", + outputFilename: "upstream-v3-output-expected.yaml", + builderType: KICV3GATEWAY, + wantErr: false, + }, + { + // Global Plugin to KongClusterPlugin. Output does not depend on KIC v2 vs v3 + name: "Kong to KIC: Global Plugin", + inputFilename: "global-plugin-input.yaml", + outputFilename: "global-plugin-output-expected.yaml", + builderType: KICV3GATEWAY, + wantErr: false, + }, + { + // Consumer to KongConsumer. Output depends on KIC v2 vs v3. + // KIC v2 uses kongCredType for credential type, KIC v3 uses labels + name: "Kong to KIC: Consumer KIC v2", + inputFilename: "consumer-input.yaml", + outputFilename: "consumer-v2-output-expected.yaml", builderType: KICV2GATEWAY, wantErr: false, }, { - name: "Kong to KIC: kic v2.x Ingress API, yaml", - inputFilename: "input.yaml", - outputFilename: "kicv2_ingress/output-expected.yaml", - builderType: KICV2INGRESS, + // Consumer to KongConsumer. Output depends on KIC v2 vs v3. + // KIC v2 uses kongCredType for credential type, KIC v3 uses labels + name: "Kong to KIC: Consumer KIC v3", + inputFilename: "consumer-input.yaml", + outputFilename: "consumer-v3-output-expected.yaml", + builderType: KICV3GATEWAY, wantErr: false, }, { - name: "Kong to KIC: kic v2.x Ingress API, json", - inputFilename: "input.yaml", - outputFilename: "kicv2_ingress/output-expected.json", - builderType: KICV2INGRESS, + // Consumer Group to KongConsumerGroup. Output does not depend on KIC v2 vs v3 + name: "Kong to KIC: ConsumerGroup", + inputFilename: "consumer-group-input.yaml", + outputFilename: "consumer-group-output-expected.yaml", + builderType: KICV3GATEWAY, + wantErr: false, + }, + { + // Certificate to Secret type: kubernetes.io/tls. + // Output does not depend on KIC v2 vs v3 + name: "Kong to KIC: Certificate", + inputFilename: "certificate-input.yaml", + outputFilename: "certificate-output-expected.yaml", + builderType: KICV3GATEWAY, + wantErr: false, + }, + { + // CA Certificate to Secret type: Opaque. + // Output does not depend on KIC v2 vs v3 + name: "Kong to KIC: CA Certificate", + inputFilename: "ca-certificate-input.yaml", + outputFilename: "ca-certificate-output-expected.yaml", + builderType: KICV3GATEWAY, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - inputContent, err := file.GetContentFromFiles([]string{baseLocation + tt.inputFilename}, false) - if err != nil { - assert.Fail(t, err.Error()) - } + inputPath := filepath.Join(baseLocation, tt.inputFilename) + inputContent, err := file.GetContentFromFiles([]string{inputPath}, false) + require.NoError(t, err) - var output []byte + outputFormat := file.YAML if strings.HasSuffix(tt.outputFilename, ".json") { - output, err = MarshalKongToKIC(inputContent, tt.builderType, file.JSON) - } else { - output, err = MarshalKongToKIC(inputContent, tt.builderType, file.YAML) + outputFormat = file.JSON } + output, err := MarshalKongToKIC(inputContent, tt.builderType, outputFormat) + if (err != nil) != tt.wantErr { + t.Errorf("MarshalKongToKIC() error = %v, wantErr %v", err, tt.wantErr) + return + } if err == nil { compareFileContent(t, tt.outputFilename, output) - } else if (err != nil) != tt.wantErr { - t.Errorf("KongToKIC() error = %v, wantErr %v", err, tt.wantErr) } }) } } + +func Test_deployManifests(t *testing.T) { + versions := []string{"2.12", "3.0", "3.1", "3.2", "3.3"} + for _, version := range versions { + t.Run("KIC Version "+version, func(t *testing.T) { + t.Parallel() + ctx := context.Background() + + // Configure the testing environment with the specified KIC version + env, kongAddon, err := setupTestingEnvironmentWithVersion(ctx, version) + require.NoError(t, err) + defer teardownEnvironment(ctx, t, env) + + t.Log("waiting for the test environment to be ready for use") + require.NoError(t, <-env.WaitForReady(ctx)) + + t.Log("verifying the test environment becomes ready for use") + waitForObjects, ready, err := env.Ready(ctx) + require.NoError(t, err) + require.Empty(t, waitForObjects) + require.True(t, ready) + + t.Log("verifying the kong proxy is returning its default 404 response") + proxyURL, err := getKongProxyURL(ctx, env) + require.NoError(t, err) + verifyKongProxyResponse(t, proxyURL) + + t.Log("verifying that the kong addon deployed both proxy and controller") + verifyKongDeployment(ctx, t, env, kongAddon) + + config := env.Cluster().Config() + + t.Log("deploying the Gateway API CRDs") + clientset, err := deployGatewayAPICRDs(t, config) + require.NoError(t, err) + + t.Log("obtaining the ServerPreferredResources from the cluster") + kindToResource, err := getKindToResourceMap(clientset) + require.NoError(t, err) + + t.Log("creating a dynamic client for Kubernetes resources") + dynamicClient, err := dynamic.NewForConfig(config) + require.NoError(t, err) + + t.Log("deploying manifests to the cluster") + err = deployManifestsToClusterForVersion(t, dynamicClient, kindToResource, version) + require.NoError(t, err) + }) + } +} + +// Helper function to set up the testing environment with a specific KIC version +func setupTestingEnvironmentWithVersion( + ctx context.Context, + kicVersion string, +) (environment.Environment, *kong.Addon, error) { + builder := environment.NewBuilder() + kongAddonBuilder := kong.NewBuilder(). + WithControllerImage("kong/kubernetes-ingress-controller", kicVersion). + WithProxyImage("kong", "3.4") // Adjust proxy image if needed + + kongAddon := kongAddonBuilder.Build() + env, err := builder.WithAddons(metallb.New(), kongAddon).Build(ctx) + if err != nil { + return nil, nil, err + } + return env, kongAddon, nil +} + +// Mutex to avoid race condition on ~/.kube/config file +var teardownMutex sync.Mutex + +func teardownEnvironment(ctx context.Context, t *testing.T, env environment.Environment) { + // Lock the mutex to ensure only one teardown process at a time + teardownMutex.Lock() + defer teardownMutex.Unlock() + + t.Logf("cleaning up environment %s and cluster %s", env.Name(), env.Cluster().Name()) + require.NoError(t, env.Cleanup(ctx)) +} + +// Helper function to get Kong proxy URL +func getKongProxyURL(ctx context.Context, env environment.Environment) (string, error) { + kongAon, err := env.Cluster().GetAddon("kong") + if err != nil { + return "", err + } + kongAddonRaw, ok := kongAon.(*kong.Addon) + if !ok { + return "", errors.New("failed to cast kong addon") + } + proxyURL, err := kongAddonRaw.ProxyHTTPURL(ctx, env.Cluster()) + if err != nil { + return "", err + } + return proxyURL.String(), nil +} + +// Helper function to verify Kong proxy response +func verifyKongProxyResponse(t *testing.T, proxyURL string) { + httpc := http.Client{Timeout: time.Second * 10} + require.Eventually(t, func() bool { + resp, err := httpc.Get(proxyURL) + if err != nil { + return false + } + defer resp.Body.Close() + return resp.StatusCode == http.StatusNotFound + }, time.Minute*3, time.Second) +} + +// Helper function to verify Kong deployment +func verifyKongDeployment(ctx context.Context, t *testing.T, env environment.Environment, kongAddon *kong.Addon) { + client := env.Cluster().Client() + appsV1 := client.AppsV1() + deployments := appsV1.Deployments(kongAddon.Namespace()) + kongDeployment, err := deployments.Get(ctx, "ingress-controller-kong", metav1.GetOptions{}) + require.NoError(t, err) + require.Len(t, kongDeployment.Spec.Template.Spec.Containers, 2) + require.Equal(t, "ingress-controller", kongDeployment.Spec.Template.Spec.Containers[0].Name) + require.Equal(t, "proxy", kongDeployment.Spec.Template.Spec.Containers[1].Name) +} + +// Helper function to deploy Gateway API CRDs +func deployGatewayAPICRDs(t *testing.T, config *rest.Config) (*clientset.Clientset, error) { + clientset, err := clientset.NewForConfig(config) + if err != nil { + return nil, err + } + + gatewayAPICrdPath := filepath.Join("testdata", "gateway-api-crd.yaml") + gatewayAPICrdFile, err := os.ReadFile(gatewayAPICrdPath) + if err != nil { + return nil, err + } + + // Split the YAML file into individual documents. + yamlDocs := regexp.MustCompile(`(?m)^---\s*$`).Split(string(gatewayAPICrdFile), -1) + + for _, doc := range yamlDocs { + if strings.TrimSpace(doc) == "" { + continue + } + + dec := yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(doc)), 4096) + var crd apiextensionsv1.CustomResourceDefinition + err := dec.Decode(&crd) + if err != nil { + return nil, err + } + + _, err = clientset.ApiextensionsV1().CustomResourceDefinitions().Create(context.TODO(), &crd, metav1.CreateOptions{}) + if err != nil { + return nil, err + } + t.Logf("created CRD: %s", crd.Name) + } + + // Wait for CRDs to be available + time.Sleep(2 * time.Second) + return clientset, nil +} + +// Helper function to get Kind to Resource mapping +func getKindToResourceMap(clientset *clientset.Clientset) (map[string]string, error) { + kindToResource := make(map[string]string) + groups, err := clientset.Discovery().ServerPreferredResources() + if err != nil { + return nil, err + } + for _, group := range groups { + for _, resource := range group.APIResources { + kindToResource[resource.Kind] = resource.Name + } + } + return kindToResource, nil +} + +// Helper function to deploy manifests to the cluster +func deployManifestsToClusterForVersion( + t *testing.T, + dynamicClient dynamic.Interface, + kindToResource map[string]string, + version string, +) error { + files, err := os.ReadDir("testdata/") + if err != nil { + return err + } + + for _, file := range files { + filename := file.Name() + if !strings.HasSuffix(filename, "output-expected.yaml") { + continue + } + // Skip files based on version + if version == "2.12" && strings.Contains(filename, "-v3-") { + continue + } + if version != "2.12" && strings.Contains(filename, "-v2-") { + continue + } + content, err := os.ReadFile(filepath.Join("testdata", filename)) + if err != nil { + return err + } + t.Logf("DEPLOYING MANIFEST: %s for KIC version %s", filename, version) + err = deployManifestToCluster(t, content, kindToResource, dynamicClient) + if err != nil { + return err + } + } + return nil +} + +// Simplify the deployManifestToCluster function +func deployManifestToCluster( + t *testing.T, + manifest []byte, + kindToResource map[string]string, + dynamicClient dynamic.Interface, +) error { + decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(manifest), 4096) + var objectsToDelete []ObjectToDelete + + for { + var rawObj unstructured.Unstructured + if err := decoder.Decode(&rawObj); err != nil { + if errors.Is(err, io.EOF) { + break + } + return err + } + + gvr, err := getGroupVersionResource(&rawObj, kindToResource) + if err != nil { + return err + } + + setNamespaceIfNeeded(&rawObj) + + _, err = dynamicClient.Resource(gvr). + Namespace(rawObj.GetNamespace()). + Create(context.TODO(), &rawObj, metav1.CreateOptions{}) + if err != nil { + return err + } + t.Logf("created object: %s of Kind: %s in Namespace: %s", rawObj.GetName(), rawObj.GetKind(), rawObj.GetNamespace()) + objectsToDelete = append(objectsToDelete, ObjectToDelete{object: rawObj, gvr: gvr}) + } + + // Clean up created objects + for _, obj := range objectsToDelete { + err := dynamicClient.Resource(obj.gvr). + Namespace(obj.object.GetNamespace()). + Delete(context.TODO(), obj.object.GetName(), metav1.DeleteOptions{}) + if err != nil { + return err + } + t.Logf("deleted object: %s of Kind: %s in Namespace: %s", + obj.object.GetName(), + obj.object.GetKind(), + obj.object.GetNamespace()) + } + return nil +} + +// Helper function to get GroupVersionResource from an unstructured object +func getGroupVersionResource( + obj *unstructured.Unstructured, + kindToResource map[string]string, +) (schema.GroupVersionResource, error) { + apiVersion := obj.GetAPIVersion() + kind := obj.GetKind() + resource, exists := kindToResource[kind] + if !exists { + return schema.GroupVersionResource{}, errors.New("resource not found for kind: " + kind) + } + + parts := strings.Split(apiVersion, "/") + if len(parts) == 2 { + return schema.GroupVersionResource{ + Group: parts[0], + Version: parts[1], + Resource: resource, + }, nil + } else if len(parts) == 1 { + return schema.GroupVersionResource{ + Group: "", + Version: parts[0], + Resource: resource, + }, nil + } + return schema.GroupVersionResource{}, errors.New("invalid apiVersion: " + apiVersion) +} + +// Helper function to set namespace if needed +func setNamespaceIfNeeded(obj *unstructured.Unstructured) { + if obj.GetKind() == "KongClusterPlugin" { + obj.SetNamespace(apiv1.NamespaceAll) + } else if obj.GetNamespace() == "" { + obj.SetNamespace(apiv1.NamespaceDefault) + } +} + +// Type definition for objects to delete +type ObjectToDelete struct { + object unstructured.Unstructured + gvr schema.GroupVersionResource +} diff --git a/kong2kic/route.go b/kong2kic/route.go index f9e797dca..0c014c7ea 100644 --- a/kong2kic/route.go +++ b/kong2kic/route.go @@ -3,229 +3,174 @@ package kong2kic import ( "encoding/json" "log" - "sort" "strconv" "strings" "github.com/kong/go-database-reconciler/pkg/file" + "github.com/kong/go-kong/kong" kicv1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1" k8snetv1 "k8s.io/api/networking/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - k8sgwapiv1 "sigs.k8s.io/gateway-api/apis/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// Convert route to Ingress (Ingress API) -func populateKICIngressesWithAnnotations(content *file.Content, kicContent *KICContent) error { - // For each route under each service create one ingress. - // If the route has multiple hosts, create the relevant host declarations in the ingress - // and under each hosts create a declaration for each path in the route. - // If the route has no hosts, create a declaration in the ingress for each path in the route. - // Map additional fields in the route to annotations in the ingress. - // If the route has plugins, create a KongPlugin for each one and add an annotation to the ingress - // to link the plugin to it. - for _, service := range content.Services { - for _, route := range service.Routes { - // save all ingresses we create for this route so we can then - // assign them the plugins defined for the route - var ( - k8sIngress k8snetv1.Ingress - pathTypeImplSpecific = k8snetv1.PathTypeImplementationSpecific - ) - - k8sIngress.TypeMeta.APIVersion = "networking.k8s.io/v1" - k8sIngress.TypeMeta.Kind = "Ingress" - if service.Name != nil && route.Name != nil { - k8sIngress.ObjectMeta.Name = calculateSlug(*service.Name + "-" + *route.Name) - } else { - log.Println("Service name or route name is empty. This is not recommended." + - "Please, provide a name for the service and the route before generating Kong Ingress Controller manifests.") - continue +// Helper function to add annotations from a route to an ingress +func addAnnotationsFromRoute(route *file.FRoute, annotations map[string]string) { + if route.Protocols != nil { + var protocols []string + for _, protocol := range route.Protocols { + if protocol != nil { + protocols = append(protocols, *protocol) } - ingressClassName := ClassName - k8sIngress.Spec.IngressClassName = &ingressClassName - k8sIngress.ObjectMeta.Annotations = make(map[string]string) - - // add konghq.com/protocols annotation if route.Protocols is not nil - if route.Protocols != nil { - var protocols string - for _, protocol := range route.Protocols { - if protocols == "" { - protocols = *protocol - } else { - protocols = protocols + "," + *protocol - } - } - k8sIngress.ObjectMeta.Annotations["konghq.com/protocols"] = protocols - } - - // add konghq.com/strip-path annotation if route.StripPath is not nil - if route.StripPath != nil { - k8sIngress.ObjectMeta.Annotations["konghq.com/strip-path"] = strconv.FormatBool(*route.StripPath) - } - - // add konghq.com/preserve-host annotation if route.PreserveHost is not nil - if route.PreserveHost != nil { - k8sIngress.ObjectMeta.Annotations["konghq.com/preserve-host"] = strconv.FormatBool(*route.PreserveHost) - } - - // add konghq.com/regex-priority annotation if route.RegexPriority is not nil - if route.RegexPriority != nil { - k8sIngress.ObjectMeta.Annotations["konghq.com/regex-priority"] = strconv.Itoa(*route.RegexPriority) + } + annotations["konghq.com/protocols"] = strings.Join(protocols, ",") + } + if route.StripPath != nil { + annotations["konghq.com/strip-path"] = strconv.FormatBool(*route.StripPath) + } + if route.PreserveHost != nil { + annotations["konghq.com/preserve-host"] = strconv.FormatBool(*route.PreserveHost) + } + if route.RegexPriority != nil { + annotations["konghq.com/regex-priority"] = strconv.Itoa(*route.RegexPriority) + } + if route.HTTPSRedirectStatusCode != nil { + annotations["konghq.com/https-redirect-status-code"] = strconv.Itoa(*route.HTTPSRedirectStatusCode) + } + if route.Headers != nil { + for key, value := range route.Headers { + annotations["konghq.com/headers."+key] = strings.Join(value, ",") + } + } + if route.PathHandling != nil { + annotations["konghq.com/path-handling"] = *route.PathHandling + } + if route.SNIs != nil { + var snis []string + for _, sni := range route.SNIs { + if sni != nil { + snis = append(snis, *sni) } - - // add konghq.com/https-redirect-status-code annotation if route.HTTPSRedirectStatusCode is not nil - if route.HTTPSRedirectStatusCode != nil { - value := strconv.Itoa(*route.HTTPSRedirectStatusCode) - k8sIngress.ObjectMeta.Annotations["konghq.com/https-redirect-status-code"] = value + } + annotations["konghq.com/snis"] = strings.Join(snis, ",") + } + if route.RequestBuffering != nil { + annotations["konghq.com/request-buffering"] = strconv.FormatBool(*route.RequestBuffering) + } + if route.ResponseBuffering != nil { + annotations["konghq.com/response-buffering"] = strconv.FormatBool(*route.ResponseBuffering) + } + if route.Methods != nil { + var methods []string + for _, method := range route.Methods { + if method != nil { + methods = append(methods, *method) } - - // add konghq.com/headers.* annotation if route.Headers is not nil - if route.Headers != nil { - for key, value := range route.Headers { - k8sIngress.ObjectMeta.Annotations["konghq.com/headers."+key] = strings.Join(value, ",") - } + } + annotations["konghq.com/methods"] = strings.Join(methods, ",") + } + if route.Tags != nil { + var tags []string + for _, tag := range route.Tags { + if tag != nil { + tags = append(tags, *tag) } + } + annotations["konghq.com/tags"] = strings.Join(tags, ",") + } +} - // add konghq.com/path-handling annotation if route.PathHandling is not nil - if route.PathHandling != nil { - k8sIngress.ObjectMeta.Annotations["konghq.com/path-handling"] = *route.PathHandling +// Helper function to create ingress paths +func createIngressPaths( + route *file.FRoute, + serviceName string, + servicePort *int, + pathType k8snetv1.PathType, +) []k8snetv1.HTTPIngressPath { + var paths []k8snetv1.HTTPIngressPath + for _, path := range route.Paths { + sCopy := *path + if strings.HasPrefix(sCopy, "~") { + sCopy = "/" + sCopy + } + backend := k8snetv1.IngressBackend{ + Service: &k8snetv1.IngressServiceBackend{ + Name: serviceName, + }, + } + if servicePort != nil { + // check that the port is within the valid range + if *servicePort > 65535 || *servicePort < 0 { + log.Fatalf("Port %d is not within the valid range. Please provide a port between 0 and 65535.\n", *servicePort) } + //nolint: gosec + backend.Service.Port.Number = int32(*servicePort) + } + paths = append(paths, k8snetv1.HTTPIngressPath{ + Path: sCopy, + PathType: &pathType, + Backend: backend, + }) + } + return paths +} - // add konghq.com/snis annotation if route.SNIs is not nil - if route.SNIs != nil { - var snis string - for _, sni := range route.SNIs { - if snis == "" { - snis = *sni - } else { - snis = snis + "," + *sni - } - } - k8sIngress.ObjectMeta.Annotations["konghq.com/snis"] = snis +// Convert route to Ingress (Ingress API) +func populateKICIngressesWithAnnotations(content *file.Content, kicContent *KICContent) error { + for _, service := range content.Services { + if service.Name == nil { + log.Println("Service name is empty. Please provide a name for the service.") + continue + } + serviceName := *service.Name + for _, route := range service.Routes { + if route.Name == nil { + log.Println("Route name is empty. Please provide a name for the route.") + continue } + routeName := *route.Name - // add konghq.com/request-buffering annotation if route.RequestBuffering is not nil - if route.RequestBuffering != nil { - k8sIngress.ObjectMeta.Annotations["konghq.com/request-buffering"] = strconv.FormatBool(*route.RequestBuffering) + k8sIngress := k8snetv1.Ingress{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "networking.k8s.io/v1", + Kind: "Ingress", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: calculateSlug(serviceName + "-" + routeName), + Annotations: make(map[string]string), + }, } + ingressClassName := ClassName + k8sIngress.Spec.IngressClassName = &ingressClassName - // add konghq.com/response-buffering annotation if route.ResponseBuffering is not nil - if route.ResponseBuffering != nil { - k8sIngress.ObjectMeta.Annotations["konghq.com/response-buffering"] = strconv.FormatBool(*route.ResponseBuffering) - } + addAnnotationsFromRoute(route, k8sIngress.ObjectMeta.Annotations) - // add konghq.com/methods annotation if route.Methods is not nil - if route.Methods != nil { - var methods string - for _, method := range route.Methods { - if methods == "" { - methods = *method - } else { - methods = methods + "," + *method - } - } - k8sIngress.ObjectMeta.Annotations["konghq.com/methods"] = methods - } + pathType := k8snetv1.PathTypeImplementationSpecific if len(route.Hosts) == 0 { - // iterate route.Paths and create a k8sIngress.Spec.Rules for each one. - // If service.Port is not nil, add it to the k8sIngress.Spec.Rules ingressRule := k8snetv1.IngressRule{ IngressRuleValue: k8snetv1.IngressRuleValue{ HTTP: &k8snetv1.HTTPIngressRuleValue{ - Paths: []k8snetv1.HTTPIngressPath{}, + Paths: createIngressPaths(route, serviceName, service.Port, pathType), }, }, } - for _, path := range route.Paths { - // if path starts with ~ then add / to the beginning of the path - // see: https://docs.konghq.com/kubernetes-ingress-controller/latest/guides/upgrade-kong-3x/#update-ingr - // ess-regular-expression-paths-for-kong-3x-compatibility - sCopy := *path - if strings.HasPrefix(*path, "~") { - sCopy = "/" + *path - } - if service.Port != nil { - ingressRule.IngressRuleValue.HTTP.Paths = append(ingressRule.IngressRuleValue.HTTP.Paths, - k8snetv1.HTTPIngressPath{ - Path: sCopy, - PathType: &pathTypeImplSpecific, - Backend: k8snetv1.IngressBackend{ - Service: &k8snetv1.IngressServiceBackend{ - Name: *service.Name, - Port: k8snetv1.ServiceBackendPort{ - Number: int32(*service.Port), //nolint:gosec - }, - }, - }, - }) - } else { - ingressRule.IngressRuleValue.HTTP.Paths = append(ingressRule.IngressRuleValue.HTTP.Paths, - k8snetv1.HTTPIngressPath{ - Path: sCopy, - PathType: &pathTypeImplSpecific, - Backend: k8snetv1.IngressBackend{ - Service: &k8snetv1.IngressServiceBackend{ - Name: *service.Name, - }, - }, - }) - } - } k8sIngress.Spec.Rules = append(k8sIngress.Spec.Rules, ingressRule) } else { - // Iterate route.Hosts and create a k8sIngress.Spec.Rules for each one. - // For each host, iterate route.Paths and add a k8snetv1.HTTPIngressPath to the k8sIngress.Spec.Rules. - // If service.Port is not nil, add it to the k8sIngress.Spec.Rules for _, host := range route.Hosts { ingressRule := k8snetv1.IngressRule{ Host: *host, IngressRuleValue: k8snetv1.IngressRuleValue{ HTTP: &k8snetv1.HTTPIngressRuleValue{ - Paths: []k8snetv1.HTTPIngressPath{}, + Paths: createIngressPaths(route, serviceName, service.Port, pathType), }, }, } - for _, path := range route.Paths { - // if path starts with ~ then add / to the beginning of the path - // see: https://docs.konghq.com/kubernetes-ingress-controller/latest/guides/upgrade-kong-3x/#update-ingr - // ess-regular-expression-paths-for-kong-3x-compatibility - sCopy := *path - if strings.HasPrefix(*path, "~") { - sCopy = "/" + *path - } - if service.Port != nil { - ingressRule.IngressRuleValue.HTTP.Paths = append(ingressRule.IngressRuleValue.HTTP.Paths, - k8snetv1.HTTPIngressPath{ - Path: sCopy, - PathType: &pathTypeImplSpecific, - Backend: k8snetv1.IngressBackend{ - Service: &k8snetv1.IngressServiceBackend{ - Name: *service.Name, - Port: k8snetv1.ServiceBackendPort{ - Number: int32(*service.Port), //nolint:gosec - }, - }, - }, - }) - } else { - ingressRule.IngressRuleValue.HTTP.Paths = append(ingressRule.IngressRuleValue.HTTP.Paths, - k8snetv1.HTTPIngressPath{ - Path: sCopy, - PathType: &pathTypeImplSpecific, - Backend: k8snetv1.IngressBackend{ - Service: &k8snetv1.IngressServiceBackend{ - Name: *service.Name, - }, - }, - }) - } - } k8sIngress.Spec.Rules = append(k8sIngress.Spec.Rules, ingressRule) } } - err := addPluginsToRoute(service, route, k8sIngress, kicContent) + err := addPluginsToRoute(service, route, &k8sIngress, kicContent) if err != nil { return err } @@ -235,319 +180,77 @@ func populateKICIngressesWithAnnotations(content *file.Content, kicContent *KICC return nil } +// Simplify the plugin addition function func addPluginsToRoute( service file.FService, route *file.FRoute, - ingress k8snetv1.Ingress, + ingress *k8snetv1.Ingress, kicContent *KICContent, ) error { for _, plugin := range route.Plugins { - var kongPlugin kicv1.KongPlugin - kongPlugin.APIVersion = KICAPIVersion - kongPlugin.Kind = KongPluginKind - if plugin.Name != nil && route.Name != nil && service.Name != nil { - kongPlugin.ObjectMeta.Name = calculateSlug(*service.Name + "-" + *route.Name + "-" + *plugin.Name) - } else { - log.Println("Service name, route name or plugin name is empty. This is not recommended." + - "Please, provide a name for the service, route and the plugin before generating Kong Ingress Controller manifests.") + if plugin.Name == nil { + log.Println("Plugin name is empty. Please provide a name for the plugin.") continue } - kongPlugin.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} - kongPlugin.PluginName = *plugin.Name - - var configJSON apiextensionsv1.JSON - var err error - configJSON.Raw, err = json.Marshal(plugin.Config) - if err != nil { - return err + pluginName := *plugin.Name + kongPlugin := kicv1.KongPlugin{ + TypeMeta: metav1.TypeMeta{ + APIVersion: KICAPIVersion, + Kind: KongPluginKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: calculateSlug(*service.Name + "-" + *route.Name + "-" + pluginName), + Annotations: map[string]string{IngressClass: ClassName}, + }, + PluginName: pluginName, } - kongPlugin.Config = configJSON - if ingress.ObjectMeta.Annotations["konghq.com/plugins"] == "" { - ingress.ObjectMeta.Annotations["konghq.com/plugins"] = kongPlugin.ObjectMeta.Name - } else { - annotations := ingress.ObjectMeta.Annotations["konghq.com/plugins"] + "," + kongPlugin.ObjectMeta.Name - ingress.ObjectMeta.Annotations["konghq.com/plugins"] = annotations + // Populate plugin fields + if plugin.Enabled != nil { + kongPlugin.Disabled = !*plugin.Enabled } - - kicContent.KongPlugins = append(kicContent.KongPlugins, kongPlugin) - } - return nil -} - -// HeadersByNameTypeAndValue is a type to sort headers by name, type and value. -// This is needed to ensure that the order of headers is consistent across runs. -type HeadersByNameTypeAndValue []k8sgwapiv1.HTTPHeaderMatch - -func (a HeadersByNameTypeAndValue) Len() int { return len(a) } -func (a HeadersByNameTypeAndValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a HeadersByNameTypeAndValue) Less(i, j int) bool { - if a[i].Name < a[j].Name { - return true - } - if a[i].Name > a[j].Name { - return false - } - - if a[i].Type != nil && a[j].Type == nil { - return true - } - if a[i].Type == nil && a[j].Type != nil { - return false - } - - if *a[i].Type < *a[j].Type { - return true - } - if *a[i].Type > *a[j].Type { - return false - } - return a[i].Value < a[j].Value -} - -// Convert route to HTTPRoute (Gateway API) -func populateKICIngressesWithGatewayAPI(content *file.Content, kicContent *KICContent) error { - for _, service := range content.Services { - for _, route := range service.Routes { - var httpRoute k8sgwapiv1.HTTPRoute - httpRoute.Kind = "HTTPRoute" - if targetKICVersionAPI == KICV3GATEWAY { - httpRoute.APIVersion = GatewayAPIVersionV1 - } else { - httpRoute.APIVersion = GatewayAPIVersionV1Beta1 - } - if service.Name != nil && route.Name != nil { - httpRoute.ObjectMeta.Name = calculateSlug(*service.Name + "-" + *route.Name) - } else { - log.Println("Service name or route name is empty. This is not recommended." + - "Please, provide a name for the service and the route before generating HTTPRoute manifests.") - continue - } - httpRoute.ObjectMeta.Annotations = make(map[string]string) - - // add konghq.com/preserve-host annotation if route.PreserveHost is not nil - if route.PreserveHost != nil { - httpRoute.ObjectMeta.Annotations["konghq.com/preserve-host"] = strconv.FormatBool(*route.PreserveHost) - } - - // add konghq.com/strip-path annotation if route.StripPath is not nil - if route.StripPath != nil { - httpRoute.ObjectMeta.Annotations["konghq.com/strip-path"] = strconv.FormatBool(*route.StripPath) - } - - // add konghq.com/https-redirect-status-code annotation if route.HTTPSRedirectStatusCode is not nil - if route.HTTPSRedirectStatusCode != nil { - value := strconv.Itoa(*route.HTTPSRedirectStatusCode) - httpRoute.ObjectMeta.Annotations["konghq.com/https-redirect-status-code"] = value - } - - // add konghq.com/regex-priority annotation if route.RegexPriority is not nil - if route.RegexPriority != nil { - httpRoute.ObjectMeta.Annotations["konghq.com/regex-priority"] = strconv.Itoa(*route.RegexPriority) - } - - // add konghq.com/path-handling annotation if route.PathHandling is not nil - if route.PathHandling != nil { - httpRoute.ObjectMeta.Annotations["konghq.com/path-handling"] = *route.PathHandling - } - - // add konghq.com/snis annotation if route.SNIs is not nil - if route.SNIs != nil { - var snis string - for _, sni := range route.SNIs { - if snis == "" { - snis = *sni - } else { - snis = snis + "," + *sni - } - } - httpRoute.ObjectMeta.Annotations["konghq.com/snis"] = snis - } - - // add konghq.com/request-buffering annotation if route.RequestBuffering is not nil - if route.RequestBuffering != nil { - httpRoute.ObjectMeta.Annotations["konghq.com/request-buffering"] = strconv.FormatBool(*route.RequestBuffering) - } - - // add konghq.com/response-buffering annotation if route.ResponseBuffering is not nil - if route.ResponseBuffering != nil { - httpRoute.ObjectMeta.Annotations["konghq.com/response-buffering"] = strconv.FormatBool(*route.ResponseBuffering) - } - - // if route.hosts is not nil, add them to the httpRoute - if route.Hosts != nil { - for _, host := range route.Hosts { - httpRoute.Spec.Hostnames = append(httpRoute.Spec.Hostnames, k8sgwapiv1.Hostname(*host)) - } - } - - // add kong as the spec.parentRef.name - httpRoute.Spec.ParentRefs = append(httpRoute.Spec.ParentRefs, k8sgwapiv1.ParentReference{ - Name: k8sgwapiv1.ObjectName(ClassName), - }) - - // add service details to HTTPBackendRef - - backendRef := k8sgwapiv1.BackendRef{ - BackendObjectReference: k8sgwapiv1.BackendObjectReference{ - Name: k8sgwapiv1.ObjectName(*service.Name), - }, - } - if service.Port != nil { - portNumber := k8sgwapiv1.PortNumber(*service.Port) //nolint:gosec - backendRef.Port = &portNumber + if plugin.RunOn != nil { + kongPlugin.RunOn = *plugin.RunOn + } + if plugin.Ordering != nil { + kongPlugin.Ordering = &kong.PluginOrdering{ + Before: plugin.Ordering.Before, + After: plugin.Ordering.After, } - - var httpHeaderMatch []k8sgwapiv1.HTTPHeaderMatch - headerMatchExact := k8sgwapiv1.HeaderMatchExact - headerMatchRegex := k8sgwapiv1.HeaderMatchRegularExpression - // if route.Headers is not nil, add them to the httpHeaderMatch - if route.Headers != nil { - for key, values := range route.Headers { - // if values has only one value and that value starts with - // the special prefix ~*, the value is interpreted as a regular expression. - if len(values) == 1 && strings.HasPrefix(values[0], "~*") { - httpHeaderMatch = append(httpHeaderMatch, k8sgwapiv1.HTTPHeaderMatch{ - Name: k8sgwapiv1.HTTPHeaderName(key), - Value: values[0][2:], - Type: &headerMatchRegex, - }) - } else { - // if multiple values are present, add them as comma separated values - // if only one value is present, add it as a single value - var value string - if len(values) > 1 { - value = strings.Join(values, ",") - } else { - value = values[0] - } - httpHeaderMatch = append(httpHeaderMatch, k8sgwapiv1.HTTPHeaderMatch{ - Name: k8sgwapiv1.HTTPHeaderName(key), - Value: value, - Type: &headerMatchExact, - }) - } + } + if plugin.Protocols != nil { + var protocols []string + for _, protocol := range plugin.Protocols { + if protocol != nil { + protocols = append(protocols, *protocol) } - sort.Sort(HeadersByNameTypeAndValue(httpHeaderMatch)) } - - // If path is not nil, then for each path, for each method, add a httpRouteRule - // to the httpRoute - if route.Paths != nil { - for _, path := range route.Paths { - var httpPathMatch k8sgwapiv1.HTTPPathMatch - pathMatchRegex := k8sgwapiv1.PathMatchRegularExpression - pathMatchPrefix := k8sgwapiv1.PathMatchPathPrefix - - if strings.HasPrefix(*path, "~") { - httpPathMatch.Type = &pathMatchRegex - regexPath := (*path)[1:] - httpPathMatch.Value = ®exPath - } else { - httpPathMatch.Type = &pathMatchPrefix - httpPathMatch.Value = path - } - - // if no method is specified, add a httpRouteRule to the httpRoute with headers and path - if route.Methods == nil { - httpRoute.Spec.Rules = append(httpRoute.Spec.Rules, k8sgwapiv1.HTTPRouteRule{ - Matches: []k8sgwapiv1.HTTPRouteMatch{ - { - Path: &httpPathMatch, - Headers: httpHeaderMatch, - }, - }, - BackendRefs: []k8sgwapiv1.HTTPBackendRef{ - { - BackendRef: backendRef, - }, - }, - }) - } - - for _, method := range route.Methods { - httpMethod := k8sgwapiv1.HTTPMethod(*method) - httpRoute.Spec.Rules = append(httpRoute.Spec.Rules, k8sgwapiv1.HTTPRouteRule{ - Matches: []k8sgwapiv1.HTTPRouteMatch{ - { - Path: &httpPathMatch, - Method: &httpMethod, - Headers: httpHeaderMatch, - }, - }, - BackendRefs: []k8sgwapiv1.HTTPBackendRef{ - { - BackendRef: backendRef, - }, - }, - }) - } - } - } else { - // If path is nil, then for each method, add a httpRouteRule - // to the httpRoute with headers and no path - for _, method := range route.Methods { - httpMethod := k8sgwapiv1.HTTPMethod(*method) - httpRoute.Spec.Rules = append(httpRoute.Spec.Rules, k8sgwapiv1.HTTPRouteRule{ - Matches: []k8sgwapiv1.HTTPRouteMatch{ - { - Method: &httpMethod, - Headers: httpHeaderMatch, - }, - }, - BackendRefs: []k8sgwapiv1.HTTPBackendRef{ - { - BackendRef: backendRef, - }, - }, - }) + kongPlugin.Protocols = kicv1.StringsToKongProtocols(protocols) + } + if plugin.Tags != nil { + var tags []string + for _, tag := range plugin.Tags { + if tag != nil { + tags = append(tags, *tag) } } - err := addPluginsToGatewayAPIRoute(service, route, httpRoute, kicContent) - if err != nil { - return err - } - kicContent.HTTPRoutes = append(kicContent.HTTPRoutes, httpRoute) - } - } - return nil -} - -func addPluginsToGatewayAPIRoute( - service file.FService, route *file.FRoute, httpRoute k8sgwapiv1.HTTPRoute, kicContent *KICContent, -) error { - for _, plugin := range route.Plugins { - var kongPlugin kicv1.KongPlugin - kongPlugin.APIVersion = KICAPIVersion - kongPlugin.Kind = KongPluginKind - if plugin.Name != nil && route.Name != nil && service.Name != nil { - kongPlugin.ObjectMeta.Name = calculateSlug(*service.Name + "-" + *route.Name + "-" + *plugin.Name) - } else { - log.Println("Service name, route name or plugin name is empty. This is not recommended." + - "Please, provide a name for the service, route and the plugin before generating Kong Ingress Controller manifests.") - continue + kongPlugin.ObjectMeta.Annotations["konghq.com/tags"] = strings.Join(tags, ",") } - kongPlugin.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} - kongPlugin.PluginName = *plugin.Name - var configJSON apiextensionsv1.JSON - var err error - configJSON.Raw, err = json.Marshal(plugin.Config) + configJSON, err := json.Marshal(plugin.Config) if err != nil { return err } - kongPlugin.Config = configJSON + kongPlugin.Config = apiextensionsv1.JSON{ + Raw: configJSON, + } - // add plugins as extensionRef under filters for every rule - for i := range httpRoute.Spec.Rules { - httpRoute.Spec.Rules[i].Filters = append(httpRoute.Spec.Rules[i].Filters, k8sgwapiv1.HTTPRouteFilter{ - ExtensionRef: &k8sgwapiv1.LocalObjectReference{ - Name: k8sgwapiv1.ObjectName(kongPlugin.ObjectMeta.Name), - Kind: KongPluginKind, - Group: "configuration.konghq.com", - }, - Type: k8sgwapiv1.HTTPRouteFilterExtensionRef, - }) + // Add plugin reference to ingress annotations + pluginsAnnotation := ingress.ObjectMeta.Annotations["konghq.com/plugins"] + if pluginsAnnotation == "" { + ingress.ObjectMeta.Annotations["konghq.com/plugins"] = kongPlugin.ObjectMeta.Name + } else { + ingress.ObjectMeta.Annotations["konghq.com/plugins"] = pluginsAnnotation + "," + kongPlugin.ObjectMeta.Name } kicContent.KongPlugins = append(kicContent.KongPlugins, kongPlugin) diff --git a/kong2kic/service.go b/kong2kic/service.go index 7ce9a06e0..756b03bb3 100644 --- a/kong2kic/service.go +++ b/kong2kic/service.go @@ -1,147 +1,159 @@ package kong2kic import ( - "encoding/json" "log" "strconv" "strings" "github.com/kong/go-database-reconciler/pkg/file" - kicv1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1" k8scorev1 "k8s.io/api/core/v1" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" ) +// Main function to populate KIC services with annotations func populateKICServicesWithAnnotations(content *file.Content, kicContent *KICContent) error { - // Iterate Kong Services and create k8s Services, - // then create KongIngress resources for Kong Service Upstream data. - // Finally, create KongPlugin resources for each plugin - // associated with the service. - for i := range content.Services { - service := content.Services[i] - - var k8sService k8scorev1.Service - var protocol k8scorev1.Protocol - - k8sService.TypeMeta.APIVersion = "v1" - k8sService.TypeMeta.Kind = "Service" - if service.Name != nil { - k8sService.ObjectMeta.Name = calculateSlug(*service.Name) - } else { - log.Println("Service name is empty. This is not recommended." + - "Please, provide a name for the service before generating Kong Ingress Controller manifests.") + for _, service := range content.Services { + if service.Name == nil { + log.Println("Service name is empty. Please provide a name for the service.") continue } - k8sService.ObjectMeta.Annotations = make(map[string]string) - // default TCP unless service.Protocol is equal to k8scorev1.ProtocolUDP - if service.Protocol != nil && k8scorev1.Protocol(strings.ToUpper(*service.Protocol)) == k8scorev1.ProtocolUDP { - protocol = k8scorev1.ProtocolUDP - } else { - protocol = k8scorev1.ProtocolTCP - } + // Create Kubernetes service + k8sService := createK8sService(&service, content.Upstreams) - if service.Port != nil { - sPort := k8scorev1.ServicePort{ - Protocol: protocol, - Port: int32(*service.Port), //nolint:gosec - TargetPort: intstr.IntOrString{ - IntVal: int32(*service.Port), //nolint:gosec - }, - } - k8sService.Spec.Ports = append(k8sService.Spec.Ports, sPort) - } + // Add annotations from the service object + addAnnotationsFromService(&service, k8sService.ObjectMeta.Annotations) - if service.Name != nil { - k8sService.Spec.Selector = map[string]string{"app": *service.Name} + // Populate upstream policies based on KIC version + if targetKICVersionAPI == KICV3GATEWAY || targetKICVersionAPI == KICV3INGRESS { + populateKICUpstreamPolicy(content, &service, k8sService, kicContent) } else { - log.Println("Service without a name is not recommended") + populateKICUpstream(content, &service, k8sService, kicContent) } - // add konghq.com/read-timeout annotation if service.ReadTimeout is not nil - if service.ReadTimeout != nil { - k8sService.ObjectMeta.Annotations["konghq.com/read-timeout"] = strconv.Itoa(*service.ReadTimeout) + // Add plugins to the service + err := addPluginsToService(&service, k8sService, kicContent) + if err != nil { + return err } - // add konghq.com/write-timeout annotation if service.WriteTimeout is not nil - if service.WriteTimeout != nil { - k8sService.ObjectMeta.Annotations["konghq.com/write-timeout"] = strconv.Itoa(*service.WriteTimeout) - } + // Append the Kubernetes service to KIC content + kicContent.Services = append(kicContent.Services, *k8sService) + } + return nil +} - // add konghq.com/connect-timeout annotation if service.ConnectTimeout is not nil - if service.ConnectTimeout != nil { - k8sService.ObjectMeta.Annotations["konghq.com/connect-timeout"] = strconv.Itoa(*service.ConnectTimeout) - } +// Helper function to create a Kubernetes Service from a Kong service +func createK8sService(service *file.FService, upstreams []file.FUpstream) *k8scorev1.Service { + k8sService := &k8scorev1.Service{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Service", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: calculateSlug(*service.Name), + Annotations: make(map[string]string), + }, + } - // add konghq.com/protocol annotation if service.Protocol is not nil - if service.Protocol != nil { - k8sService.ObjectMeta.Annotations["konghq.com/protocol"] = *service.Protocol - } + // Determine the protocol (default to TCP) + protocol := k8scorev1.ProtocolTCP + if service.Protocol != nil && strings.ToUpper(*service.Protocol) == string(k8scorev1.ProtocolUDP) { + protocol = k8scorev1.ProtocolUDP + } - // add konghq.com/path annotation if service.Path is not nil - if service.Path != nil { - k8sService.ObjectMeta.Annotations["konghq.com/path"] = *service.Path + // Set the service port + if service.Port != nil { + // check that the port is within the valid range + if *service.Port > 65535 || *service.Port < 0 { + log.Fatalf("Port %d is not within the valid range. Please provide a port between 0 and 65535.\n", *service.Port) } - - // add konghq.com/retries annotation if service.Retries is not nil - if service.Retries != nil { - k8sService.ObjectMeta.Annotations["konghq.com/retries"] = strconv.Itoa(*service.Retries) + servicePort := k8scorev1.ServicePort{ + Protocol: protocol, + //nolint: gosec + Port: int32(*service.Port), + TargetPort: intstr.FromInt(*service.Port), } + k8sService.Spec.Ports = []k8scorev1.ServicePort{servicePort} + } - if targetKICVersionAPI == KICV3GATEWAY || targetKICVersionAPI == KICV3INGRESS { - // Use KongUpstreamPolicy for KICv3 - populateKICUpstreamPolicy(content, &service, &k8sService, kicContent) - } else { - // Use KongIngress for KICv2 - populateKICUpstream(content, &service, &k8sService, kicContent) - } + // Configure the service selector or external name + if service.Host == nil { + k8sService.Spec.Selector = map[string]string{"app": *service.Name} + } else { + k8sService.Spec.Type = k8scorev1.ServiceTypeExternalName + k8sService.Spec.ExternalName = *service.Host - // iterate over the plugins for this service, create a KongPlugin for each one and add an annotation to the service - // transform the plugin config from map[string]interface{} to apiextensionsv1.JSON - // create a plugins annotation in the k8sservice to link the plugin to it - err := addPluginsToService(service, k8sService, kicContent) - if err != nil { - return err + // Check if the host matches any upstream + if isUpstreamReferenced(service.Host, upstreams) { + k8sService.Spec.Selector = map[string]string{"app": *service.Name} + k8sService.Spec.Type = "" + k8sService.Spec.ExternalName = "" } + } - kicContent.Services = append(kicContent.Services, k8sService) + return k8sService +} +// Helper function to check if the service host matches any upstream name +func isUpstreamReferenced(host *string, upstreams []file.FUpstream) bool { + for _, upstream := range upstreams { + if upstream.Name != nil && strings.EqualFold(*upstream.Name, *host) { + return true + } } - return nil + return false } -func addPluginsToService(service file.FService, k8sService k8scorev1.Service, kicContent *KICContent) error { +// Helper function to add annotations from a service to a Kubernetes service +func addAnnotationsFromService(service *file.FService, annotations map[string]string) { + if service.Protocol != nil { + annotations["konghq.com/protocol"] = *service.Protocol + } + if service.Path != nil { + annotations["konghq.com/path"] = *service.Path + } + if service.ClientCertificate != nil && service.ClientCertificate.ID != nil { + annotations["konghq.com/client-cert"] = *service.ClientCertificate.ID + } + if service.ReadTimeout != nil { + annotations["konghq.com/read-timeout"] = strconv.Itoa(*service.ReadTimeout) + } + if service.WriteTimeout != nil { + annotations["konghq.com/write-timeout"] = strconv.Itoa(*service.WriteTimeout) + } + if service.ConnectTimeout != nil { + annotations["konghq.com/connect-timeout"] = strconv.Itoa(*service.ConnectTimeout) + } + if service.Retries != nil { + annotations["konghq.com/retries"] = strconv.Itoa(*service.Retries) + } + addTagsToAnnotations(service.Tags, annotations) +} + +// Helper function to add plugins to a service +func addPluginsToService(service *file.FService, k8sService *k8scorev1.Service, kicContent *KICContent) error { for _, plugin := range service.Plugins { - var kongPlugin kicv1.KongPlugin - kongPlugin.APIVersion = KICAPIVersion - kongPlugin.Kind = KongPluginKind - if plugin.Name != nil && service.Name != nil { - kongPlugin.ObjectMeta.Name = calculateSlug(*service.Name + "-" + *plugin.Name) - } else { - log.Println("Service name or plugin name is empty. This is not recommended." + - "Please, provide a name for the service and the plugin before generating Kong Ingress Controller manifests.") + if plugin.Name == nil || service.Name == nil { + log.Println("Service name or plugin name is empty. Please provide names for both.") continue } - kongPlugin.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} - kongPlugin.PluginName = *plugin.Name - var configJSON apiextensionsv1.JSON - var err error - configJSON.Raw, err = json.Marshal(plugin.Config) + // Create a KongPlugin + kongPlugin, err := createKongPlugin(plugin, *service.Name) if err != nil { return err } - kongPlugin.Config = configJSON - - if k8sService.ObjectMeta.Annotations["konghq.com/plugins"] == "" { - k8sService.ObjectMeta.Annotations["konghq.com/plugins"] = kongPlugin.ObjectMeta.Name - } else { - annotations := k8sService.ObjectMeta.Annotations["konghq.com/plugins"] + "," + kongPlugin.ObjectMeta.Name - k8sService.ObjectMeta.Annotations["konghq.com/plugins"] = annotations + if kongPlugin == nil { + continue } - kicContent.KongPlugins = append(kicContent.KongPlugins, kongPlugin) + // Add the plugin name to the service annotations + addPluginToAnnotations(kongPlugin.ObjectMeta.Name, k8sService.ObjectMeta.Annotations) + + // Append the KongPlugin to KIC content + kicContent.KongPlugins = append(kicContent.KongPlugins, *kongPlugin) } return nil } diff --git a/kong2kic/testdata/README.md b/kong2kic/testdata/README.md new file mode 100644 index 000000000..f187b1662 --- /dev/null +++ b/kong2kic/testdata/README.md @@ -0,0 +1,64 @@ + +# Service +- A Kong Service maps to a Kubernetes Service. +- The generated k8s service is independent of KIC version or GW/INGRESS API. +- For each Kong service, it creates a new Kubernetes service. +- If the service has a name, it is converted into a slug format using the calculateSlug function and assigned to the Kubernetes service's name. +- If the service doesn't have a name, a warning message is logged and it is skipped. +- The protocol defaults to TCP unless the service's protocol is explicitly set to UDP. +- If the service has a specified port, a ServicePort object is created with the protocol and port information, and this object is appended to the Kubernetes service's ports. +- The service name, is used as a selector for the Kubernetes service. +- Various properties of the service (like ReadTimeout, WriteTimeout, ConnectTimeout, Protocol, Path, and Retries) are added as annotations to the Kubernetes service. +- If the service host is informed then search for an Upstream which name matches. If there is no upstream, then configure an external service. + +# Route +- A Kong Route maps to a HTTPRoute (Gateway API) or Ingress (Ingress API) + +## Ingress API +- The generated k8s Ingress is independent of KIC version. +- If the service and route names are not nil, they are used to generate a slug that is used as the name of the Ingress resource. If either the service or route name is nil, a log message is printed and the loop continues to the next iteration. +- It then checks various properties of the route (like Protocols, StripPath, PreserveHost, etc.) and if they are not nil, it adds corresponding annotations to the k8sIngress. +- If the route doesn't have hosts defined, it creates an IngressRule for each path in the route. +- If the service has a port, it is included in the IngressRule. +- If the route does have hosts, it creates an IngressRule for each host and for each path in the route. Again, if the service has a port, +it is included in the IngressRule. + +## Gateway API +- The generated k8s HTTPRoute is slighlty different for KIC v2 vs v3. The only difference is `apiVersion: gateway.networking.k8s.io/v1beta1` vs `apiVersion: gateway.networking.k8s.io/v1`. +- If the service and route names are not nil, they are used to generate a slug that is used as the name of the Ingress resource. If either the service or route name is nil, a log message is printed and the loop continues to the next iteration. +- It then checks various properties of the route (like Protocols, StripPath, PreserveHost, etc.) and if they are not nil, it adds corresponding annotations. +- It then checks if route.Hosts is not nil and if it's not, it appends each host to httpRoute.Spec.Hostnames. It also appends a ParentReference with the name "kong" to httpRoute.Spec.ParentRefs. +- It then creates a BackendRef with the service name and port and assigns it to backendRef. It also creates an HTTPHeaderMatch slice and populates it with header matches if route.Headers is not nil. +- Next, the function checks if route.Paths is not nil and if it's not, it creates an HTTPRouteRule for each path and each method in the route and +appends it to httpRoute.Spec.Rules. If route.Paths is nil, it creates an HTTPRouteRule for each method in the route with no path and appends it to httpRoute.Spec.Rules + +# Plugin +## Service and Route plugins +- A Kong Plugin maps to a KongPlugin in K8s. +- Plugins do not depend on KIC v2 vs v3. +- The plugin configuration is copied verbatim and an annotation is added to the entity to which the plugin is applied (Service, Ingress, Consumer, ConsumerGroup) +- HTTPRoute is a special case in which the plugin is referenced as an extensionRef and not an annotation. + +## Global Plugins +- A Kong Global Plugin maps to a KongClusterPlugin. +- The plugin configuration is copied verbatim. + +## Consumer Group Plugin +- A Kong Consumer Group plugin maps to a KongPlugin. +- It's treated differently because the Kong Consumer Group plugin fields are different. + +# Consumer +- A Consumer maps to a KongConsumer object. +- Its credentials are mapped to Secrets in K8s. + +# Consumer Group +- A Consumer Group is mapped to a KongConsumerGroup. + +# Certificate +- A certificate is mapped to a Secret of type "kubernetes.io/tls". + +# CA Certificate +- A CA Certificate maps to an Opaque Secret. + +# Upstream +- An Upstream maps to a KongIngress for KIC v2 and to a KongUpstreamPolicy for KIC v3. diff --git a/kong2kic/testdata/ca-certificate-input.yaml b/kong2kic/testdata/ca-certificate-input.yaml new file mode 100644 index 000000000..c3c991e2a --- /dev/null +++ b/kong2kic/testdata/ca-certificate-input.yaml @@ -0,0 +1,49 @@ +ca_certificates: +- cert: | + -----BEGIN CERTIFICATE----- + MIIBfDCCASKgAwIBAgIRAJqcZC1VSvSQLMN1+7yAeswwCgYIKoZIzj0EAwIwHDEa + MBgGA1UEAxMRRGVtbyBLb25nIFJvb3QgQ0EwHhcNMjIwNjEzMTMzNzMzWhcNMjcw + NjEzMTkzNzMzWjAcMRowGAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTBZMBMGByqG + SM49AgEGCCqGSM49AwEHA0IABOGR89IyhreSHRAi6wp9a5DBIDp4YYSdWzuEdlNx + 7pX1G4T7x68xUXJZXRUPFyT8Xzn5KwCJm8RVT+nAhrsUx6SjRTBDMA4GA1UdDwEB + /wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBQ9CUiOPhjp7KD2 + ScRDxX4IzDOrNzAKBggqhkjOPQQDAgNIADBFAiEAw6Dov0c0L++1W9VufAfSMdNR + PSDfPU0MiUiG59/VIBICIEFn/6c5eQc3hUUBL74/RmNT2b1zxBmp7RiPXJAnAAwJ + -----END CERTIFICATE----- + cert_digest: f1baffe9fe9cf8497e38a4271d67fab44423678b7e7c0f677a50f37c113d81b5 + id: 8ccca140-aff4-411d-8e1c-fcfb3f932a8e + tags: + - root-ca +- cert: | + -----BEGIN CERTIFICATE----- + MIIBqTCCAVCgAwIBAgIQb5LqGa9gS3+Mc2ntWfSoJjAKBggqhkjOPQQDAjAcMRow + GAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTAeFw0yMjA2MTMxMzM5MTVaFw0yMzA2 + MTMxOTM5MTVaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBSb290IEludGVybWVkaWF0 + ZTEgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQImvnSuvXkGy88lvx8a7of + e0MEMRI2siVvybvWXNpeXXlixgaq7weJ7pewf3HywfO68Va6kn8ehWh7s0D7SLHM + o2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4E + FgQUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwHwYDVR0jBBgwFoAUPQlIjj4Y6eyg9knE + Q8V+CMwzqzcwCgYIKoZIzj0EAwIDRwAwRAIgNZ+JPA1OqF5DsPapAZ2YsUOgIpn3 + ZbQuYKCAV0SD4EcCIFnfA5rWrc1AgtUw5inJQqJQRNgoPuC14vACqI48BiRl + -----END CERTIFICATE----- + cert_digest: dbef7ed285fb292e24f84ffba93c48d92fa322387d85469c460c655abedd5308 + id: 2e5f8ad1-21ca-47f5-8af7-899486e82731 + tags: + - intermediate_ca1 +- cert: | + -----BEGIN CERTIFICATE----- + MIIBujCCAV+gAwIBAgIRAMkGpj7WZf+2RFE/q7ZhejEwCgYIKoZIzj0EAwIwKjEo + MCYGA1UEAxMfRGVtbyBLb25nIFJvb3QgSW50ZXJtZWRpYXRlMSBDQTAeFw0yMjA2 + MTMxMzQwNTFaFw0yMjEyMTMwNDQwNTFaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBS + b290IEludGVybWVkaWF0ZTIgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQB + my/zhZ3F2HvHFqtQzuD3lXX8SeYakxiBQvaGkGSLKD67N3vh7iC2rTSdj/vAs8ws + Y9X+mXzS6GDKC8PbSX6xo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgw + BgEB/wIBADAdBgNVHQ4EFgQURwCm53YPStZoAMfnVyknH4IgZa4wHwYDVR0jBBgw + FoAUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwCgYIKoZIzj0EAwIDSQAwRgIhAN1pkUKc + azM4PiXOnkILB2KBDIF4XpHf+4ThDMODzXP8AiEA45KXA3qMrRPQV1oBfWZ3hLgX + gxUhveuHBXMWnzUbn6U= + -----END CERTIFICATE----- + cert_digest: 45b2b6dd9d4102955b1b1e4b540e677f140521462ed4f22fa5a713863ca84600 + id: cab2565d-fed6-4a07-b25c-bab76fdfe071 + tags: + - intermediate_ca2 diff --git a/kong2kic/testdata/ca-certificate-output-expected.yaml b/kong2kic/testdata/ca-certificate-output-expected.yaml new file mode 100644 index 000000000..e16719041 --- /dev/null +++ b/kong2kic/testdata/ca-certificate-output-expected.yaml @@ -0,0 +1,69 @@ +apiVersion: v1 +kind: Secret +metadata: + annotations: + konghq.com/tags: root-ca + kubernetes.io/ingress.class: kong + name: ca-cert-a672ab52d2341203bd70116b456413d7ac3ffc162abbf +stringData: + ca.crt: | + -----BEGIN CERTIFICATE----- + MIIBfDCCASKgAwIBAgIRAJqcZC1VSvSQLMN1+7yAeswwCgYIKoZIzj0EAwIwHDEa + MBgGA1UEAxMRRGVtbyBLb25nIFJvb3QgQ0EwHhcNMjIwNjEzMTMzNzMzWhcNMjcw + NjEzMTkzNzMzWjAcMRowGAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTBZMBMGByqG + SM49AgEGCCqGSM49AwEHA0IABOGR89IyhreSHRAi6wp9a5DBIDp4YYSdWzuEdlNx + 7pX1G4T7x68xUXJZXRUPFyT8Xzn5KwCJm8RVT+nAhrsUx6SjRTBDMA4GA1UdDwEB + /wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBQ9CUiOPhjp7KD2 + ScRDxX4IzDOrNzAKBggqhkjOPQQDAgNIADBFAiEAw6Dov0c0L++1W9VufAfSMdNR + PSDfPU0MiUiG59/VIBICIEFn/6c5eQc3hUUBL74/RmNT2b1zxBmp7RiPXJAnAAwJ + -----END CERTIFICATE----- + ca.digest: f1baffe9fe9cf8497e38a4271d67fab44423678b7e7c0f677a50f37c113d81b5 +type: Opaque +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + konghq.com/tags: intermediate_ca1 + kubernetes.io/ingress.class: kong + name: ca-cert-a4f087c2ee00e6d43cfb4f6884fc1e79f7e6e08e84471 +stringData: + ca.crt: | + -----BEGIN CERTIFICATE----- + MIIBqTCCAVCgAwIBAgIQb5LqGa9gS3+Mc2ntWfSoJjAKBggqhkjOPQQDAjAcMRow + GAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTAeFw0yMjA2MTMxMzM5MTVaFw0yMzA2 + MTMxOTM5MTVaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBSb290IEludGVybWVkaWF0 + ZTEgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQImvnSuvXkGy88lvx8a7of + e0MEMRI2siVvybvWXNpeXXlixgaq7weJ7pewf3HywfO68Va6kn8ehWh7s0D7SLHM + o2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4E + FgQUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwHwYDVR0jBBgwFoAUPQlIjj4Y6eyg9knE + Q8V+CMwzqzcwCgYIKoZIzj0EAwIDRwAwRAIgNZ+JPA1OqF5DsPapAZ2YsUOgIpn3 + ZbQuYKCAV0SD4EcCIFnfA5rWrc1AgtUw5inJQqJQRNgoPuC14vACqI48BiRl + -----END CERTIFICATE----- + ca.digest: dbef7ed285fb292e24f84ffba93c48d92fa322387d85469c460c655abedd5308 +type: Opaque +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + konghq.com/tags: intermediate_ca2 + kubernetes.io/ingress.class: kong + name: ca-cert-6b095c7ff377b01252a4dfec59c582fe32934fa7ed0cf +stringData: + ca.crt: | + -----BEGIN CERTIFICATE----- + MIIBujCCAV+gAwIBAgIRAMkGpj7WZf+2RFE/q7ZhejEwCgYIKoZIzj0EAwIwKjEo + MCYGA1UEAxMfRGVtbyBLb25nIFJvb3QgSW50ZXJtZWRpYXRlMSBDQTAeFw0yMjA2 + MTMxMzQwNTFaFw0yMjEyMTMwNDQwNTFaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBS + b290IEludGVybWVkaWF0ZTIgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQB + my/zhZ3F2HvHFqtQzuD3lXX8SeYakxiBQvaGkGSLKD67N3vh7iC2rTSdj/vAs8ws + Y9X+mXzS6GDKC8PbSX6xo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgw + BgEB/wIBADAdBgNVHQ4EFgQURwCm53YPStZoAMfnVyknH4IgZa4wHwYDVR0jBBgw + FoAUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwCgYIKoZIzj0EAwIDSQAwRgIhAN1pkUKc + azM4PiXOnkILB2KBDIF4XpHf+4ThDMODzXP8AiEA45KXA3qMrRPQV1oBfWZ3hLgX + gxUhveuHBXMWnzUbn6U= + -----END CERTIFICATE----- + ca.digest: 45b2b6dd9d4102955b1b1e4b540e677f140521462ed4f22fa5a713863ca84600 +type: Opaque +--- diff --git a/kong2kic/testdata/certificate-input.yaml b/kong2kic/testdata/certificate-input.yaml new file mode 100644 index 000000000..b071d064e --- /dev/null +++ b/kong2kic/testdata/certificate-input.yaml @@ -0,0 +1,146 @@ +certificates: +- cert: |- + -----BEGIN CERTIFICATE----- + MIIECTCCAvGgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyAwDQYJKoZIhvcNAQEL + BQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM + CUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY + MBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u + Z2hxLmNvbTAeFw0yMTAxMTUxMTE5NDNaFw0yMjA1MzAxMTE5NDNaMIGRMQswCQYD + VQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx + EDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFzAVBgNVBAMMDnBy + b3h5LmtvbmcubGFuMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29uZ2hxLmNvbTCCASIw + DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJUbKiqoCK1BTNk/7l42n6ukyTEu + eLyB23e/90PzT/oz8wZzgwTodzbFAS2VtFr1EKqFzor0DrXp9CLnebOdiAR3I6LD + /WY/x0KW3lx3F35fGiUOSLPTH8zeiDTMx11CcKDxesA+M2/s5q0igkOQ4z4w3voz + m5a52IcQTSA8K5knNU1qUZBLpc+khxFcaheEK1jsISJJhcdizZBfGdk8S1vpyj5F + uCZ7oaRvNA6imHjSJwpgo36zd84TgrIgVj9R4QtJysWy/X+bbaKUiKBWwAtd4+DT + EP90l/ny9szu2fijk4/6k1ntXufGTyvM+J0/qJ13e99TVYOVanITnpTO+6cCAwEA + AaNWMFQwHwYDVR0jBBgwFoAUdskpf0wJRQxjtzQFZciWmUfl2bcwCQYDVR0TBAIw + ADALBgNVHQ8EBAMCBPAwGQYDVR0RBBIwEIIOcHJveHkua29uZy5sYW4wDQYJKoZI + hvcNAQELBQADggEBAJVrTWQRQzNtypa9OXFYADm8Fay1VMop3BY2kh0tfYgQEJ/4 + pJUj6CaszQZ/Aix6LaPnXFcoPCDqqv00mgju86PMamr/zA9USXk8eTmzJkp5RklS + GdqiXboqESiQVvaNz3kdW7wgNz4FwaGCzkEi/dcc2LdtzLpWizx+TlxMMqjonUUM + ovZgZo+OlhWRsDVT/qy5SFtA0vlVNtdBr2egXb1H7J8UDC+fax/iKa7+fBUHZOO9 + Fk9U8bxgfQ+jPIVVL8CfAtR68Sos7NpWH0S2emqZRnQvf0MSNdkTQKWn4qR9sckj + Ewxs5FbrMmgCOgwk1PtgRmdP3RME0HwK/B03saQ= + -----END CERTIFICATE----- + id: 507cc555-5b92-496d-9e89-bfc78dfcddbe + key: |- + -----BEGIN PRIVATE KEY----- + MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCVGyoqqAitQUzZ + P+5eNp+rpMkxLni8gdt3v/dD80/6M/MGc4ME6Hc2xQEtlbRa9RCqhc6K9A616fQi + 53mznYgEdyOiw/1mP8dClt5cdxd+XxolDkiz0x/M3og0zMddQnCg8XrAPjNv7Oat + IoJDkOM+MN76M5uWudiHEE0gPCuZJzVNalGQS6XPpIcRXGoXhCtY7CEiSYXHYs2Q + XxnZPEtb6co+Rbgme6GkbzQOoph40icKYKN+s3fOE4KyIFY/UeELScrFsv1/m22i + lIigVsALXePg0xD/dJf58vbM7tn4o5OP+pNZ7V7nxk8rzPidP6idd3vfU1WDlWpy + E56UzvunAgMBAAECggEAcq7lHNAHdHLgT8yrY41x/AwPryNGO/9JNW7SGVKAdjoU + tyaLZHAEmXynLk+R28/YFMA8H4Yd9m9OlrYhVjRZFM4p+5vxP/7YHPB7cPUsfcda + DZxR8PX25JVYf/vtb16V0ERLnKd62qCEwC/lr2A2WHQwXJLrHeAtmZzBJYUCJ5Xj + Dv1ZhyFjknswaV0vGXe6njTI6CzMQDTGysoagpCCo7RWgzjLREg2BGWd2UQpY4AW + nYAP4QNt82UMQbgIqsEMj64mzS9Q+o1P84J1naSP5sCI22LeFRp6iezZc+D8EH/5 + RNONGSNWl3g6bsvN1VywYwjWn+waD3XAjXUu+peUgQKBgQDDu1QP28oSMKivHdfo + kQ1HrTNBRc9eWeAMZFuIbbPLN8rdEibpOm3DwTqithnahqS0NLOsBnXNtuLw1Qr/ + zmOzn0yDO5XG8dlKr9vqWeBLdcRydLJBZwqEzWf4JwwwgfK3rItRaIbnAxnGUTS5 + SrrhNfBAIGS9jx5X2kvLC7hFQQKBgQDDBIrpLTIjRDloWZcu03z9Bhb8jQCyGb5C + 4MYs+duCnQIdNq/+maPspJzbVmF4b6S1zIPweI3fMvMeqRTbuf+drpElst1buFTO + P0UMMn4V+4qGIOOkIy5JIKwR8sJD9tNDUPtxuDEotTB9IyWx6pdmCFz5v/bggDCu + reoqflL+5wKBgQCDvb+L2QS+j4/KJk0flRoaJ2K7SVCVEesyjA3r2uLMImZhvAkC + rDgbLSDZSbZHFp8fR+WzILoD11gSf2Ki4PjMeqkWH3HlcP0vPwTHTO0h/UdXPmKI + kOFMl7CmHyoeMCj9JZ60EaXTMYwUpq3VFY6JbTOjBeqoh/8FZMHlDaNewQKBgCHg + ECEg8KyflTlDFrfTlMp+3E9STuShBCOp18LIRBEUJOHeNgQLvCXHElgnURcSjZHm + zKRgzIQQ3Zpd1Hm2fWhuglgCEeF0y4ZoBx5vRueaoh1aaTCBy/B39GvJt2UG4vu2 + fXbrf96KWrnh+RJGpbXbjgr0BXZJzisJmrt25gPRAoGBAI3c+INpQXwrE+LBzCPu + LwIVvkm5NpeIlKQtDNrqG1QvUhqyZ2/Xitc4FyiccW7WHxkGKGZyj7GbmpqEOnyY + iVku0LSftZgycet2uMdp0HaVAgi5S6aVf5yN0U/8R5ToxcbuEfqwrBIyRgse8lx3 + NNSvLxPAempmiFPSk9AtobYV + -----END PRIVATE KEY----- + snis: + - name: proxy.kong.lan + tags: + - proxy.kong.lan +- cert: |- + -----BEGIN CERTIFICATE----- + MIIFeDCCBGCgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyQwDQYJKoZIhvcNAQEL + BQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM + CUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY + MBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u + Z2hxLmNvbTAeFw0yMTAxMjAxNTA0NDVaFw0yMjAxMjAxNTA0NDVaMIGQMQswCQYD + VQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx + EDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFjAUBgNVBAMMDW10 + bHMtY29uc3VtZXIxHTAbBgkqhkiG9w0BCQEWDnN0dUBrb25naHEuY29tMIICIjAN + BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1/+83/YNiEVKYvcuVwYGve6afsg1 + BYCn1+E9Uwgh0uwAenT/DKB8NhqoVxc7cZ2HaTI146IGmFICmctlTWvLPLglHmTo + byOUV6tIJAjvzyEOpC458hLGgbv8mhGXJWPxBVu7Wy6Hapz2bk0cEscfL7PHKaRu + 3D6r8/zbhhWAqe4EIt+NVYT6baaYBs7bPZQXs/sluKI+DNYuDeaAmoSuCc4ein6z + 0xDqCSMmPebzjns03ttB29vWL3eYY9dvgoCd+CPhXT/C4CHtvKbH+hOQYDtVF6MO + 1mmABAQTQWMR/00+QI0xtvuXtEPurla5dA0TN6ddCTOOcILKx62z5oc3Kqr+nHHa + 71zNzARUVaZ2vy1pRVr0DZgB7KqcFXhy/oy8IpmxUR1ASBDZl6B6RKrdQwvgLgmn + 3M/roNLAU+3nz4itpt/zf+X0suwdthrflic1R68z1SlYbyoGARWkZ/pOl6kLNVK2 + OsqQuICaajnW7t1oDd7z1+3hm+uoryDwvG6f3T9ZvWjKXYcKg7b+BjbFdahbDywD + PgnhSz9AaoVWhR+GHIPrjRClMpEkra/yGJFvH3UpXhgg9d0DrLZE51Z75a9SvnAj + vdLuNhx4bJbwLBgNGsJMkupzBrw4iCfbKFcBbP8o0Xjtarj7T/mkWuQ1GjWqfyrD + 55NecBPNw5C9BR0CAwEAAaOBxTCBwjAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQE + AwIFoDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgQ2xpZW50IENl + cnRpZmljYXRlMB0GA1UdDgQWBBSV3F+eicU8SVT4LcDJ6eMzP0todzAfBgNVHSME + GDAWgBR2ySl/TAlFDGO3NAVlyJaZR+XZtzAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0l + BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4IBAQB5L0OZ + WELG9Pw6Ol1BsZYgpLR4PGNBB9dKm/9dd+q+ohZVFCfXcjZ3YOU1vh/HHQrALRNY + I58JxcVCOx/qIW2uA0iSCqIT0sNb9cJLxfZf7X+BzPPPnu0ugUJp7GzLNnHitrLC + Xb1nmmefwgraNzp+a5IrR8RcQG1mYDuS+2HK/rybo22XcCxhob8OiDEn8+ytkKyQ + Ipmrf9D+/68/ih6az0w1aakASMmFe8z/p6VgVQkCySCWWFG525BRdGmSImqVZ4xa + aQFN3L+oN+JJcCFTthLOAYo32JH+xLMz7PokzSL84g3b68h59hXDoMSwB10GthL5 + T8tqV6i5miKWwvfZ + -----END CERTIFICATE----- + id: f3ae1bb2-ea6a-4caf-a7a7-2f078b7842db + key: |- + -----BEGIN RSA PRIVATE KEY----- + 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 + -----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/kong2kic/testdata/certificate-output-expected.yaml b/kong2kic/testdata/certificate-output-expected.yaml new file mode 100644 index 000000000..744685098 --- /dev/null +++ b/kong2kic/testdata/certificate-output-expected.yaml @@ -0,0 +1,158 @@ +apiVersion: v1 +kind: Secret +metadata: + annotations: + konghq.com/tags: proxy.kong.lan + kubernetes.io/ingress.class: kong + name: cert-0ee0e1584c8637facac95bd5fce315367dee124c0086d41e +stringData: + tls.crt: |- + -----BEGIN CERTIFICATE----- + MIIECTCCAvGgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyAwDQYJKoZIhvcNAQEL + BQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM + CUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY + MBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u + Z2hxLmNvbTAeFw0yMTAxMTUxMTE5NDNaFw0yMjA1MzAxMTE5NDNaMIGRMQswCQYD + VQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx + EDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFzAVBgNVBAMMDnBy + b3h5LmtvbmcubGFuMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29uZ2hxLmNvbTCCASIw + DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJUbKiqoCK1BTNk/7l42n6ukyTEu + eLyB23e/90PzT/oz8wZzgwTodzbFAS2VtFr1EKqFzor0DrXp9CLnebOdiAR3I6LD + /WY/x0KW3lx3F35fGiUOSLPTH8zeiDTMx11CcKDxesA+M2/s5q0igkOQ4z4w3voz + m5a52IcQTSA8K5knNU1qUZBLpc+khxFcaheEK1jsISJJhcdizZBfGdk8S1vpyj5F + uCZ7oaRvNA6imHjSJwpgo36zd84TgrIgVj9R4QtJysWy/X+bbaKUiKBWwAtd4+DT + EP90l/ny9szu2fijk4/6k1ntXufGTyvM+J0/qJ13e99TVYOVanITnpTO+6cCAwEA + AaNWMFQwHwYDVR0jBBgwFoAUdskpf0wJRQxjtzQFZciWmUfl2bcwCQYDVR0TBAIw + ADALBgNVHQ8EBAMCBPAwGQYDVR0RBBIwEIIOcHJveHkua29uZy5sYW4wDQYJKoZI + hvcNAQELBQADggEBAJVrTWQRQzNtypa9OXFYADm8Fay1VMop3BY2kh0tfYgQEJ/4 + pJUj6CaszQZ/Aix6LaPnXFcoPCDqqv00mgju86PMamr/zA9USXk8eTmzJkp5RklS + GdqiXboqESiQVvaNz3kdW7wgNz4FwaGCzkEi/dcc2LdtzLpWizx+TlxMMqjonUUM + ovZgZo+OlhWRsDVT/qy5SFtA0vlVNtdBr2egXb1H7J8UDC+fax/iKa7+fBUHZOO9 + Fk9U8bxgfQ+jPIVVL8CfAtR68Sos7NpWH0S2emqZRnQvf0MSNdkTQKWn4qR9sckj + Ewxs5FbrMmgCOgwk1PtgRmdP3RME0HwK/B03saQ= + -----END CERTIFICATE----- + tls.key: |- + -----BEGIN PRIVATE KEY----- + MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCVGyoqqAitQUzZ + P+5eNp+rpMkxLni8gdt3v/dD80/6M/MGc4ME6Hc2xQEtlbRa9RCqhc6K9A616fQi + 53mznYgEdyOiw/1mP8dClt5cdxd+XxolDkiz0x/M3og0zMddQnCg8XrAPjNv7Oat + IoJDkOM+MN76M5uWudiHEE0gPCuZJzVNalGQS6XPpIcRXGoXhCtY7CEiSYXHYs2Q + XxnZPEtb6co+Rbgme6GkbzQOoph40icKYKN+s3fOE4KyIFY/UeELScrFsv1/m22i + lIigVsALXePg0xD/dJf58vbM7tn4o5OP+pNZ7V7nxk8rzPidP6idd3vfU1WDlWpy + E56UzvunAgMBAAECggEAcq7lHNAHdHLgT8yrY41x/AwPryNGO/9JNW7SGVKAdjoU + tyaLZHAEmXynLk+R28/YFMA8H4Yd9m9OlrYhVjRZFM4p+5vxP/7YHPB7cPUsfcda + DZxR8PX25JVYf/vtb16V0ERLnKd62qCEwC/lr2A2WHQwXJLrHeAtmZzBJYUCJ5Xj + Dv1ZhyFjknswaV0vGXe6njTI6CzMQDTGysoagpCCo7RWgzjLREg2BGWd2UQpY4AW + nYAP4QNt82UMQbgIqsEMj64mzS9Q+o1P84J1naSP5sCI22LeFRp6iezZc+D8EH/5 + RNONGSNWl3g6bsvN1VywYwjWn+waD3XAjXUu+peUgQKBgQDDu1QP28oSMKivHdfo + kQ1HrTNBRc9eWeAMZFuIbbPLN8rdEibpOm3DwTqithnahqS0NLOsBnXNtuLw1Qr/ + zmOzn0yDO5XG8dlKr9vqWeBLdcRydLJBZwqEzWf4JwwwgfK3rItRaIbnAxnGUTS5 + SrrhNfBAIGS9jx5X2kvLC7hFQQKBgQDDBIrpLTIjRDloWZcu03z9Bhb8jQCyGb5C + 4MYs+duCnQIdNq/+maPspJzbVmF4b6S1zIPweI3fMvMeqRTbuf+drpElst1buFTO + P0UMMn4V+4qGIOOkIy5JIKwR8sJD9tNDUPtxuDEotTB9IyWx6pdmCFz5v/bggDCu + reoqflL+5wKBgQCDvb+L2QS+j4/KJk0flRoaJ2K7SVCVEesyjA3r2uLMImZhvAkC + rDgbLSDZSbZHFp8fR+WzILoD11gSf2Ki4PjMeqkWH3HlcP0vPwTHTO0h/UdXPmKI + kOFMl7CmHyoeMCj9JZ60EaXTMYwUpq3VFY6JbTOjBeqoh/8FZMHlDaNewQKBgCHg + ECEg8KyflTlDFrfTlMp+3E9STuShBCOp18LIRBEUJOHeNgQLvCXHElgnURcSjZHm + zKRgzIQQ3Zpd1Hm2fWhuglgCEeF0y4ZoBx5vRueaoh1aaTCBy/B39GvJt2UG4vu2 + fXbrf96KWrnh+RJGpbXbjgr0BXZJzisJmrt25gPRAoGBAI3c+INpQXwrE+LBzCPu + LwIVvkm5NpeIlKQtDNrqG1QvUhqyZ2/Xitc4FyiccW7WHxkGKGZyj7GbmpqEOnyY + iVku0LSftZgycet2uMdp0HaVAgi5S6aVf5yN0U/8R5ToxcbuEfqwrBIyRgse8lx3 + NNSvLxPAempmiFPSk9AtobYV + -----END PRIVATE KEY----- +type: kubernetes.io/tls +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + kubernetes.io/ingress.class: kong + name: cert-b12464ec431576239dd9cc2545d528f6cbdbd988cf076323 +stringData: + tls.crt: |- + -----BEGIN CERTIFICATE----- + MIIFeDCCBGCgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyQwDQYJKoZIhvcNAQEL + BQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM + CUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY + MBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u + Z2hxLmNvbTAeFw0yMTAxMjAxNTA0NDVaFw0yMjAxMjAxNTA0NDVaMIGQMQswCQYD + VQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx + EDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFjAUBgNVBAMMDW10 + bHMtY29uc3VtZXIxHTAbBgkqhkiG9w0BCQEWDnN0dUBrb25naHEuY29tMIICIjAN + BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1/+83/YNiEVKYvcuVwYGve6afsg1 + BYCn1+E9Uwgh0uwAenT/DKB8NhqoVxc7cZ2HaTI146IGmFICmctlTWvLPLglHmTo + byOUV6tIJAjvzyEOpC458hLGgbv8mhGXJWPxBVu7Wy6Hapz2bk0cEscfL7PHKaRu + 3D6r8/zbhhWAqe4EIt+NVYT6baaYBs7bPZQXs/sluKI+DNYuDeaAmoSuCc4ein6z + 0xDqCSMmPebzjns03ttB29vWL3eYY9dvgoCd+CPhXT/C4CHtvKbH+hOQYDtVF6MO + 1mmABAQTQWMR/00+QI0xtvuXtEPurla5dA0TN6ddCTOOcILKx62z5oc3Kqr+nHHa + 71zNzARUVaZ2vy1pRVr0DZgB7KqcFXhy/oy8IpmxUR1ASBDZl6B6RKrdQwvgLgmn + 3M/roNLAU+3nz4itpt/zf+X0suwdthrflic1R68z1SlYbyoGARWkZ/pOl6kLNVK2 + OsqQuICaajnW7t1oDd7z1+3hm+uoryDwvG6f3T9ZvWjKXYcKg7b+BjbFdahbDywD + PgnhSz9AaoVWhR+GHIPrjRClMpEkra/yGJFvH3UpXhgg9d0DrLZE51Z75a9SvnAj + vdLuNhx4bJbwLBgNGsJMkupzBrw4iCfbKFcBbP8o0Xjtarj7T/mkWuQ1GjWqfyrD + 55NecBPNw5C9BR0CAwEAAaOBxTCBwjAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQE + AwIFoDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgQ2xpZW50IENl + cnRpZmljYXRlMB0GA1UdDgQWBBSV3F+eicU8SVT4LcDJ6eMzP0todzAfBgNVHSME + GDAWgBR2ySl/TAlFDGO3NAVlyJaZR+XZtzAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0l + BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4IBAQB5L0OZ + WELG9Pw6Ol1BsZYgpLR4PGNBB9dKm/9dd+q+ohZVFCfXcjZ3YOU1vh/HHQrALRNY + I58JxcVCOx/qIW2uA0iSCqIT0sNb9cJLxfZf7X+BzPPPnu0ugUJp7GzLNnHitrLC + Xb1nmmefwgraNzp+a5IrR8RcQG1mYDuS+2HK/rybo22XcCxhob8OiDEn8+ytkKyQ + Ipmrf9D+/68/ih6az0w1aakASMmFe8z/p6VgVQkCySCWWFG525BRdGmSImqVZ4xa + aQFN3L+oN+JJcCFTthLOAYo32JH+xLMz7PokzSL84g3b68h59hXDoMSwB10GthL5 + T8tqV6i5miKWwvfZ + -----END CERTIFICATE----- + tls.key: |- + -----BEGIN RSA PRIVATE KEY----- + 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 + -----END RSA PRIVATE KEY----- +type: kubernetes.io/tls +--- diff --git a/kong2kic/testdata/consumer-group-input.yaml b/kong2kic/testdata/consumer-group-input.yaml new file mode 100644 index 000000000..69bba14ec --- /dev/null +++ b/kong2kic/testdata/consumer-group-input.yaml @@ -0,0 +1,19 @@ +consumers: + - username: example-consumer-group-user + tags: + - internal +consumer_groups: + - name: example-consumer-group + consumers: + - username: example-consumer-group-user + plugins: + - name: rate-limiting + config: + second: 5 + hour: 10000 + policy: local + tags: + - internal-gold-users + + + \ No newline at end of file diff --git a/kong2kic/testdata/consumer-group-output-expected.yaml b/kong2kic/testdata/consumer-group-output-expected.yaml new file mode 100644 index 000000000..1f2f93ebf --- /dev/null +++ b/kong2kic/testdata/consumer-group-output-expected.yaml @@ -0,0 +1,32 @@ +apiVersion: configuration.konghq.com/v1 +config: + hour: 10000 + policy: local + second: 5 +kind: KongPlugin +metadata: + annotations: + kubernetes.io/ingress.class: kong + name: example-consumer-group-rate-limiting +plugin: rate-limiting +--- +apiVersion: configuration.konghq.com/v1 +consumerGroups: +- example-consumer-group +kind: KongConsumer +metadata: + annotations: + konghq.com/tags: internal + kubernetes.io/ingress.class: kong + name: example-consumer-group-user +username: example-consumer-group-user +--- +apiVersion: configuration.konghq.com/v1beta1 +kind: KongConsumerGroup +metadata: + annotations: + konghq.com/plugins: example-consumer-group-rate-limiting + konghq.com/tags: internal-gold-users + kubernetes.io/ingress.class: kong + name: example-consumer-group +--- diff --git a/kong2kic/testdata/consumer-input.yaml b/kong2kic/testdata/consumer-input.yaml new file mode 100644 index 000000000..ce86e6e33 --- /dev/null +++ b/kong2kic/testdata/consumer-input.yaml @@ -0,0 +1,43 @@ +consumers: + - username: example-user + custom_id: "1234567890" + tags: + - internal + acls: + - group: acl_group + tags: + - internal + basicauth_credentials: + - username: my_basic_user + password: my_basic_password + tags: + - internal + jwt_secrets: + - key: my_jwt_secret + algorithm: HS256 + secret: my_secret_key + rsa_public_key: |- + -----BEGIN PUBLIC KEY----- + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxXzYS5yESbekTF3xLiQX + ZZZfXt0S/nzFp3f2Oux3W7/ydvZ8XSd8+s+wm5oqEcSV9n+5n3ENZbt1A/wgnGI3 + oWrv0yRB9HugzTIGPpI1AQv9Z4p8E44RrB74/uTxYwb9+4yvpuz/fzTt3Gz+Kzc4 + 4fGGq8VpGMFj6AE65ZcOAHHUJe4VuoreBXLYDJcHl2WPIdNKDGscFjElDneLRhWQ + DfxekDJIQMWCjyBEXacfP6cc9U8Qld6TuVcwi1P2xb8tBDD4MIFL/psfzUhfv1Lw + O/XZEffJxCqkQn7dsCYy3wpaTjb6XmJ5j0Dbml4f0Bv40Y1mjlAf7C662Mbuguf6 + ewIDAQAB + -----END PUBLIC KEY----- + tags: + - internal + keyauth_credentials: + - key: my_api_key + tags: + - internal + mtls_auth_credentials: + - id: cce8c384-721f-4f58-85dd-50834e3e733a + subject_name: example-user@example.com + plugins: + - name: rate-limiting + config: + second: 5 + hour: 10000 + policy: local \ No newline at end of file diff --git a/kong2kic/testdata/consumer-v2-output-expected.yaml b/kong2kic/testdata/consumer-v2-output-expected.yaml new file mode 100644 index 000000000..9978ab114 --- /dev/null +++ b/kong2kic/testdata/consumer-v2-output-expected.yaml @@ -0,0 +1,94 @@ +apiVersion: configuration.konghq.com/v1 +config: + hour: 10000 + policy: local + second: 5 +kind: KongPlugin +metadata: + annotations: + kubernetes.io/ingress.class: kong + name: example-user-rate-limiting +plugin: rate-limiting +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + kubernetes.io/ingress.class: kong + name: key-auth-example-user +stringData: + key: my_api_key + kongCredType: key-auth +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + kubernetes.io/ingress.class: kong + name: jwt-auth-example-user +stringData: + algorithm: HS256 + key: my_jwt_secret + kongCredType: jwt + rsa_public_key: |- + -----BEGIN PUBLIC KEY----- + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxXzYS5yESbekTF3xLiQX + ZZZfXt0S/nzFp3f2Oux3W7/ydvZ8XSd8+s+wm5oqEcSV9n+5n3ENZbt1A/wgnGI3 + oWrv0yRB9HugzTIGPpI1AQv9Z4p8E44RrB74/uTxYwb9+4yvpuz/fzTt3Gz+Kzc4 + 4fGGq8VpGMFj6AE65ZcOAHHUJe4VuoreBXLYDJcHl2WPIdNKDGscFjElDneLRhWQ + DfxekDJIQMWCjyBEXacfP6cc9U8Qld6TuVcwi1P2xb8tBDD4MIFL/psfzUhfv1Lw + O/XZEffJxCqkQn7dsCYy3wpaTjb6XmJ5j0Dbml4f0Bv40Y1mjlAf7C662Mbuguf6 + ewIDAQAB + -----END PUBLIC KEY----- + secret: my_secret_key +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + kubernetes.io/ingress.class: kong + name: basic-auth-example-user +stringData: + kongCredType: basic-auth + password: my_basic_password + username: my_basic_user +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + kubernetes.io/ingress.class: kong + name: acl-group-example-user +stringData: + group: acl_group + kongCredType: acl +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + kubernetes.io/ingress.class: kong + name: mtls-auth-example-user +stringData: + id: cce8c384-721f-4f58-85dd-50834e3e733a + kongCredType: mtls-auth + subject_name: example-user@example.com +type: Opaque +--- +apiVersion: configuration.konghq.com/v1 +credentials: +- key-auth-example-user +- jwt-auth-example-user +- basic-auth-example-user +- acl-group-example-user +- mtls-auth-example-user +custom_id: "1234567890" +kind: KongConsumer +metadata: + annotations: + konghq.com/plugins: example-user-rate-limiting + konghq.com/tags: internal + kubernetes.io/ingress.class: kong + name: example-user +username: example-user +--- diff --git a/kong2kic/testdata/consumer-v3-output-expected.yaml b/kong2kic/testdata/consumer-v3-output-expected.yaml new file mode 100644 index 000000000..6e843caad --- /dev/null +++ b/kong2kic/testdata/consumer-v3-output-expected.yaml @@ -0,0 +1,99 @@ +apiVersion: configuration.konghq.com/v1 +config: + hour: 10000 + policy: local + second: 5 +kind: KongPlugin +metadata: + annotations: + kubernetes.io/ingress.class: kong + name: example-user-rate-limiting +plugin: rate-limiting +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + kubernetes.io/ingress.class: kong + labels: + konghq.com/credential: key-auth + name: key-auth-example-user +stringData: + key: my_api_key +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + kubernetes.io/ingress.class: kong + labels: + konghq.com/credential: jwt + name: jwt-auth-example-user +stringData: + algorithm: HS256 + key: my_jwt_secret + rsa_public_key: |- + -----BEGIN PUBLIC KEY----- + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxXzYS5yESbekTF3xLiQX + ZZZfXt0S/nzFp3f2Oux3W7/ydvZ8XSd8+s+wm5oqEcSV9n+5n3ENZbt1A/wgnGI3 + oWrv0yRB9HugzTIGPpI1AQv9Z4p8E44RrB74/uTxYwb9+4yvpuz/fzTt3Gz+Kzc4 + 4fGGq8VpGMFj6AE65ZcOAHHUJe4VuoreBXLYDJcHl2WPIdNKDGscFjElDneLRhWQ + DfxekDJIQMWCjyBEXacfP6cc9U8Qld6TuVcwi1P2xb8tBDD4MIFL/psfzUhfv1Lw + O/XZEffJxCqkQn7dsCYy3wpaTjb6XmJ5j0Dbml4f0Bv40Y1mjlAf7C662Mbuguf6 + ewIDAQAB + -----END PUBLIC KEY----- + secret: my_secret_key +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + kubernetes.io/ingress.class: kong + labels: + konghq.com/credential: basic-auth + name: basic-auth-example-user +stringData: + password: my_basic_password + username: my_basic_user +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + kubernetes.io/ingress.class: kong + labels: + konghq.com/credential: acl + name: acl-group-example-user +stringData: + group: acl_group +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + kubernetes.io/ingress.class: kong + labels: + konghq.com/credential: mtls-auth + name: mtls-auth-example-user +stringData: + id: cce8c384-721f-4f58-85dd-50834e3e733a + subject_name: example-user@example.com +type: Opaque +--- +apiVersion: configuration.konghq.com/v1 +credentials: +- key-auth-example-user +- jwt-auth-example-user +- basic-auth-example-user +- acl-group-example-user +- mtls-auth-example-user +custom_id: "1234567890" +kind: KongConsumer +metadata: + annotations: + konghq.com/plugins: example-user-rate-limiting + konghq.com/tags: internal + kubernetes.io/ingress.class: kong + name: example-user +username: example-user +--- diff --git a/kong2kic/testdata/gateway-api-crd.yaml b/kong2kic/testdata/gateway-api-crd.yaml new file mode 100644 index 000000000..ef536cb90 --- /dev/null +++ b/kong2kic/testdata/gateway-api-crd.yaml @@ -0,0 +1,7137 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/2466 + gateway.networking.k8s.io/bundle-version: v1.0.0 + 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. \n 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. \n 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. \n 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. \n Example: \"example.net/gateway-controller\". + \n This field is not mutable and cannot be empty. \n 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. \n 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. \n If the + referent cannot be found, the GatewayClass's \"InvalidParameters\" + status condition will be true. \n 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: Waiting + status: Unknown + type: Accepted + description: "Status defines the current state of GatewayClass. \n 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. \n 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. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + 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. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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: {} + - 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. \n 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. \n 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. \n 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. \n Example: \"example.net/gateway-controller\". + \n This field is not mutable and cannot be empty. \n 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. \n 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. \n If the + referent cannot be found, the GatewayClass's \"InvalidParameters\" + status condition will be true. \n 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: Waiting + status: Unknown + type: Accepted + description: "Status defines the current state of GatewayClass. \n 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. \n 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. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + 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. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/2466 + gateway.networking.k8s.io/bundle-version: v1.0.0 + 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. \n 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. \n If no Addresses + are specified, the implementation MAY schedule the Gateway in an + implementation-specific manner, assigning an appropriate set of + Addresses. \n The implementation MUST bind all Listeners to every + GatewayAddress that it assigns to the Gateway and add a corresponding + entry in GatewayStatus.Addresses. \n Support: Extended \n " + 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. \n + 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 + 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. \n 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). \n Practically, this means that each + listener in a set MUST have a unique combination of Port, Protocol, + and, if supported by the protocol, Hostname. \n Some combinations + of port, protocol, and TLS settings are considered Core support + and MUST be supported by implementations based on their targeted + conformance profile: \n HTTP Profile \n 1. HTTPRoute, Port: 80, + Protocol: HTTP 2. HTTPRoute, Port: 443, Protocol: HTTPS, TLS Mode: + Terminate, TLS keypair provided \n TLS Profile \n 1. TLSRoute, Port: + 443, Protocol: TLS, TLS Mode: Passthrough \n \"Distinct\" Listeners + have the following property: \n 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. \n For example, the following + Listener scenarios are distinct: \n 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. + \n 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. \n 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. \n 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. \n 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 `\"\"`. \n 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. \n 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\"`. \n 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\". \n 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. \n 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. \n A Gateway's Listeners are considered \"compatible\" + if: \n 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. \n 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. \n 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. + \n 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. + \n Implementations MAY merge separate Gateways onto a single set + of Addresses if all Listeners across all Gateways are compatible. + \n 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. \n 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: \n * 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. \n + 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. \n 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. \n 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. \n 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. \n Support: + Core" + properties: + from: + default: Same + description: "From indicates where Routes will be selected + for this Gateway. Possible values are: \n * 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. \n 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\". \n 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 + 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 + 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. \n Implementations + MUST apply Hostname matching appropriately for each of the + following protocols: \n * 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. \n 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. \n 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`. \n 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. \n 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. + \n Support: Core" + format: int32 + maximum: 65535 + minimum: 1 + type: integer + protocol: + description: "Protocol specifies the network protocol this listener + expects to receive. \n Support: Core" + maxLength: 255 + minLength: 1 + pattern: ^[a-zA-Z0-9]([-a-zSA-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\". \n The association + of SNIs to Certificate defined in GatewayTLSConfig is defined + based on the Hostname field for this listener. \n The GatewayClass + MUST use the longest matching SNI out of all available certificates + for any TLS handshake. \n 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. \n 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. + \n 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. \n This + field is required to have at least one element when the + mode is set to \"Terminate\" (default) and is optional + otherwise. \n CertificateRefs can reference to standard + Kubernetes resources, i.e. Secret, or implementation-specific + custom resources. \n Support: Core - A single reference + to a Kubernetes Secret of type kubernetes.io/tls \n Support: + Implementation-specific (More than one reference or other + resource types)" + items: + description: "SecretObjectReference identifies an API + object including its namespace, defaulting to Secret. + \n 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. \n 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. \n 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. + \n 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: \n - Terminate: The TLS session between the downstream + client and the Gateway is terminated at the Gateway. This + mode requires certificateRefs to be set and contain at + least one element. - 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. CertificateRefs field is + ignored in this mode. \n 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. \n 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. \n Support: Implementation-specific" + maxProperties: 16 + type: object + type: object + x-kubernetes-validations: + - message: certificateRefs must be specified when TLSModeType + is Terminate + rule: 'self.mode == ''Terminate'' ? size(self.certificateRefs) + > 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 be specified for protocols ['HTTPS', 'TLS'] + rule: 'self.all(l, l.protocol in [''HTTPS'', ''TLS''] ? has(l.tls) + : true)' + - 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: 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. \n This list may differ from the addresses + provided in the spec under some conditions: \n * 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) \n " + 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. \n + 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. + \n 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. \n Known condition types are: \n * \"Accepted\" + * \"Programmed\" * \"Ready\"" + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + 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. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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. + \n 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. \n 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. --- This struct + is intended for direct use as an array at the field path + .status.conditions. For example, \n type FooStatus struct{ + // Represents the observations of a foo's current state. + // Known .status.conditions.type are: \"Available\", \"Progressing\", + and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields + }" + 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. + --- Many .condition.type values are consistent across + resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability + to deconflict is important. The regex it matches is + (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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. + \n 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: {} + - 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. \n 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. \n If no Addresses + are specified, the implementation MAY schedule the Gateway in an + implementation-specific manner, assigning an appropriate set of + Addresses. \n The implementation MUST bind all Listeners to every + GatewayAddress that it assigns to the Gateway and add a corresponding + entry in GatewayStatus.Addresses. \n Support: Extended \n " + 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. \n + 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 + 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. \n 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). \n Practically, this means that each + listener in a set MUST have a unique combination of Port, Protocol, + and, if supported by the protocol, Hostname. \n Some combinations + of port, protocol, and TLS settings are considered Core support + and MUST be supported by implementations based on their targeted + conformance profile: \n HTTP Profile \n 1. HTTPRoute, Port: 80, + Protocol: HTTP 2. HTTPRoute, Port: 443, Protocol: HTTPS, TLS Mode: + Terminate, TLS keypair provided \n TLS Profile \n 1. TLSRoute, Port: + 443, Protocol: TLS, TLS Mode: Passthrough \n \"Distinct\" Listeners + have the following property: \n 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. \n For example, the following + Listener scenarios are distinct: \n 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. + \n 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. \n 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. \n 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. \n 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 `\"\"`. \n 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. \n 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\"`. \n 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\". \n 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. \n 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. \n A Gateway's Listeners are considered \"compatible\" + if: \n 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. \n 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. \n 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. + \n 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. + \n Implementations MAY merge separate Gateways onto a single set + of Addresses if all Listeners across all Gateways are compatible. + \n 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. \n 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: \n * 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. \n + 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. \n 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. \n 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. \n 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. \n Support: + Core" + properties: + from: + default: Same + description: "From indicates where Routes will be selected + for this Gateway. Possible values are: \n * 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. \n 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\". \n 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 + 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 + 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. \n Implementations + MUST apply Hostname matching appropriately for each of the + following protocols: \n * 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. \n 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. \n 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`. \n 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. \n 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. + \n Support: Core" + format: int32 + maximum: 65535 + minimum: 1 + type: integer + protocol: + description: "Protocol specifies the network protocol this listener + expects to receive. \n Support: Core" + maxLength: 255 + minLength: 1 + pattern: ^[a-zA-Z0-9]([-a-zSA-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\". \n The association + of SNIs to Certificate defined in GatewayTLSConfig is defined + based on the Hostname field for this listener. \n The GatewayClass + MUST use the longest matching SNI out of all available certificates + for any TLS handshake. \n 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. \n 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. + \n 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. \n This + field is required to have at least one element when the + mode is set to \"Terminate\" (default) and is optional + otherwise. \n CertificateRefs can reference to standard + Kubernetes resources, i.e. Secret, or implementation-specific + custom resources. \n Support: Core - A single reference + to a Kubernetes Secret of type kubernetes.io/tls \n Support: + Implementation-specific (More than one reference or other + resource types)" + items: + description: "SecretObjectReference identifies an API + object including its namespace, defaulting to Secret. + \n 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. \n 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. \n 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. + \n 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: \n - Terminate: The TLS session between the downstream + client and the Gateway is terminated at the Gateway. This + mode requires certificateRefs to be set and contain at + least one element. - 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. CertificateRefs field is + ignored in this mode. \n 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. \n 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. \n Support: Implementation-specific" + maxProperties: 16 + type: object + type: object + x-kubernetes-validations: + - message: certificateRefs must be specified when TLSModeType + is Terminate + rule: 'self.mode == ''Terminate'' ? size(self.certificateRefs) + > 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 be specified for protocols ['HTTPS', 'TLS'] + rule: 'self.all(l, l.protocol in [''HTTPS'', ''TLS''] ? has(l.tls) + : true)' + - 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: 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. \n This list may differ from the addresses + provided in the spec under some conditions: \n * 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) \n " + 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. \n + 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. + \n 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. \n Known condition types are: \n * \"Accepted\" + * \"Programmed\" * \"Ready\"" + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + 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. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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. + \n 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. \n 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. --- This struct + is intended for direct use as an array at the field path + .status.conditions. For example, \n type FooStatus struct{ + // Represents the observations of a foo's current state. + // Known .status.conditions.type are: \"Available\", \"Progressing\", + and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields + }" + 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. + --- Many .condition.type values are consistent across + resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability + to deconflict is important. The regex it matches is + (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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. + \n 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: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/2466 + gateway.networking.k8s.io/bundle-version: v1.0.0 + 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. \n Valid values for Hostnames + are determined by RFC 1123 definition of a hostname with 2 notable + exceptions: \n 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. \n 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: + \n * 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. \n 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`. \n 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. \n 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. \n 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: \n * Characters in a matching + non-wildcard hostname. * Characters in a matching hostname. \n If + ties exist across multiple Routes, the matching precedence rules + for HTTPRouteMatches takes over. \n 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: \n 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. \n 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`). + \n 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. \n There are two kinds of parent resources with \"Core\" + support: \n * Gateway (Gateway conformance profile) This API may + be extended in the future to support additional kinds of parent + resources. \n ParentRefs must be _distinct_. This means either that: + \n * 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. \n Some examples: + \n * 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`. \n 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. \n 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. \n \n " + 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: \n * Gateway (Gateway conformance profile) * Service + (Mesh conformance profile, experimental, ClusterIP Services only) + \n This API may be extended in the future to support additional + kinds of parent resources. \n 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). \n 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. \n There are two + kinds of parent resources with \"Core\" support: \n * Gateway + (Gateway conformance profile) * Service (Mesh conformance + profile, experimental, ClusterIP Services only) \n 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. \n 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. + \n 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. + \n \n Support: Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + sectionName: + description: "SectionName is the name of a section within the + target resource. In the following resources, SectionName is + interpreted as the following: \n * 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. Note that attaching + Routes to Services as Parents is part of experimental Mesh + support and is not supported for any other purpose. \n Implementations + MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName + is interpreted. \n 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. \n 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. \n Failure behavior here depends + on how many BackendRefs are specified and how many are invalid. + \n 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. \n + See the HTTPBackendRef definition for the rules about what + makes a single HTTPBackendRef invalid. \n 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. + \n 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. + \n Support: Core for Kubernetes Service \n Support: Extended + for Kubernetes ServiceImport \n Support: Implementation-specific + for any other resource \n Support for weight: Core" + items: + description: "HTTPBackendRef defines how a HTTPRoute forwards + a HTTP request. \n 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. \n + \n When the BackendRef points to a Kubernetes Service, implementations + SHOULD honor the appProtocol field if it is set for the + target Service Port. \n Implementations supporting appProtocol + SHOULD recognize the Kubernetes Standard Application Protocols + defined in KEP-3726. \n 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. \n 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. \n + " + 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. \n 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. \n This filter can be used multiple times + within the same rule. \n 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. \n + 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. \n Input: GET /foo HTTP/1.1 + my-header: foo \n Config: add: - name: \"my-header\" + value: \"bar,baz\" \n 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). + \n 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). + \n Input: GET /foo HTTP/1.1 my-header1: foo + my-header2: bar my-header3: baz \n Config: + remove: [\"my-header1\", \"my-header3\"] \n + 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. \n Input: GET /foo HTTP/1.1 my-header: + foo \n Config: set: - name: \"my-header\" + value: \"bar\" \n 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). + \n 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. \n 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. \n Support: Extended" + properties: + backendRef: + description: "BackendRef references a resource + where mirrored requests are sent. \n Mirrored + requests must be sent only to a single destination + endpoint within this BackendRef, irrespective + of how many endpoints are present within this + BackendRef. \n 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. + \n 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. \n In either error + case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about + the problem. \n Support: Extended for Kubernetes + Service \n 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\". + \n Defaults to \"Service\" when not specified. + \n 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. \n Support: Core (Services with + a type other than ExternalName) \n 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. \n 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. \n 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. \n 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. + \n 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. \n 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\". \n 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. + \n 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`. \n Request Path + | Prefix Match | Replace Prefix | Modified + Path -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | + /xyz/bar /foo/bar | /foo | + /xyz/ | /xyz/bar /foo/bar | + /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | + /xyz/bar /foo | /foo | + /xyz | /xyz /foo/ | /foo + \ | /xyz | /xyz/ /foo/bar + \ | /foo | | + /bar /foo/ | /foo | | / /foo | /foo | + | / /foo/ | /foo + \ | / | / /foo | + /foo | / | /" + 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. \n Note + that values may be added to this enum, + implementations must ensure that unknown + values will not cause a crash. \n 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. \n If no port is specified, the + redirect port MUST be derived using the following + rules: \n * 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. \n Implementations SHOULD NOT + add the port number in the 'Location' header + in the following cases: \n * 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. \n 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. \n Scheme redirects can affect the + port of the redirect, for more information, + refer to the documentation for the port field + of this filter. \n Note that values may be + added to this enum, implementations must ensure + that unknown values will not cause a crash. + \n Unknown values here must result in the + implementation setting the Accepted Condition + for the Route to `status: False`, with a Reason + of `UnsupportedValue`. \n Support: Extended" + enum: + - http + - https + type: string + statusCode: + default: 302 + description: "StatusCode is the HTTP status + code to be used in response. \n Note that + values may be added to this enum, implementations + must ensure that unknown values will not cause + a crash. \n Unknown values here must result + in the implementation setting the Accepted + Condition for the Route to `status: False`, + with a Reason of `UnsupportedValue`. \n Support: + Core" + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: "ResponseHeaderModifier defines a schema + for a filter that modifies response headers. \n + 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. \n Input: GET /foo HTTP/1.1 + my-header: foo \n Config: add: - name: \"my-header\" + value: \"bar,baz\" \n 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). + \n 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). + \n Input: GET /foo HTTP/1.1 my-header1: foo + my-header2: bar my-header3: baz \n Config: + remove: [\"my-header1\", \"my-header3\"] \n + 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. \n Input: GET /foo HTTP/1.1 my-header: + foo \n Config: set: - name: \"my-header\" + value: \"bar\" \n 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). + \n 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: \n - + Core: Filter types and their corresponding configuration + defined by \"Support: Core\" in this package, + e.g. \"RequestHeaderModifier\". All implementations + must support core filters. \n - Extended: Filter + types and their corresponding configuration defined + by \"Support: Extended\" in this package, e.g. + \"RequestMirror\". Implementers are encouraged + to support extended filters. \n - 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. \n Implementers are encouraged + to define custom implementation types to extend + the core API with implementation-specific behavior. + \n 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. \n + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause + a crash. \n 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. + \n Support: Extended" + properties: + hostname: + description: "Hostname is the value to be used + to replace the Host header value during forwarding. + \n 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. \n + 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\". \n 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. + \n 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`. \n Request Path + | Prefix Match | Replace Prefix | Modified + Path -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | + /xyz/bar /foo/bar | /foo | + /xyz/ | /xyz/bar /foo/bar | + /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | + /xyz/bar /foo | /foo | + /xyz | /xyz /foo/ | /foo + \ | /xyz | /xyz/ /foo/bar + \ | /foo | | + /bar /foo/ | /foo | | / /foo | /foo | + | / /foo/ | /foo + \ | / | / /foo | + /foo | / | /" + 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. \n Note + that values may be added to this enum, + implementations must ensure that unknown + values will not cause a crash. \n 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\". \n Defaults to + \"Service\" when not specified. \n 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. + \n Support: Core (Services with a type other than ExternalName) + \n 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. \n + 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. \n 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. \n + 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. \n 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. \n The effects of ordering + of multiple behaviors are currently unspecified. This can + change in the future based on feedback during the alpha stage. + \n Conformance-levels at this level are defined based on the + type of filter: \n - 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. \n Specifying + the same filter multiple times is not supported unless explicitly + indicated in the filter. \n 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. \n 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. \n This filter can be used multiple times within + the same rule. \n 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. \n 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. \n Input: GET /foo HTTP/1.1 my-header: foo + \n Config: add: - name: \"my-header\" value: \"bar,baz\" + \n 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). + \n 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). + \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: + bar my-header3: baz \n Config: remove: [\"my-header1\", + \"my-header3\"] \n 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. \n + Input: GET /foo HTTP/1.1 my-header: foo \n Config: + set: - name: \"my-header\" value: \"bar\" \n 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). + \n 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. \n 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. \n + Support: Extended" + properties: + backendRef: + description: "BackendRef references a resource where + mirrored requests are sent. \n Mirrored requests + must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many + endpoints are present within this BackendRef. \n + 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. \n 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. \n In either error case, the Message + of the `ResolvedRefs` Condition should be used to + provide more detail about the problem. \n Support: + Extended for Kubernetes Service \n 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\". + \n Defaults to \"Service\" when not specified. + \n 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. \n Support: Core (Services with a + type other than ExternalName) \n 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. \n 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. \n 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. + \n 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. \n 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. \n 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\". + \n 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. \n 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`. \n Request Path | Prefix + Match | Replace Prefix | Modified Path -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | + /xyz/bar /foo/bar | /foo | /xyz/ + \ | /xyz/bar /foo/bar | /foo/ | + /xyz | /xyz/bar /foo/bar | /foo/ + \ | /xyz/ | /xyz/bar /foo | + /foo | /xyz | /xyz /foo/ | + /foo | /xyz | /xyz/ /foo/bar + \ | /foo | | /bar + /foo/ | /foo | + | / /foo | /foo | + | / /foo/ | /foo | / | + / /foo | /foo | / | + /" + 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. \n Note that values may be added + to this enum, implementations must ensure that + unknown values will not cause a crash. \n 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. \n If + no port is specified, the redirect port MUST be + derived using the following rules: \n * 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. + \n Implementations SHOULD NOT add the port number + in the 'Location' header in the following cases: + \n * 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. \n 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. \n + Scheme redirects can affect the port of the redirect, + for more information, refer to the documentation + for the port field of this filter. \n Note that + values may be added to this enum, implementations + must ensure that unknown values will not cause a + crash. \n Unknown values here must result in the + implementation setting the Accepted Condition for + the Route to `status: False`, with a Reason of `UnsupportedValue`. + \n Support: Extended" + enum: + - http + - https + type: string + statusCode: + default: 302 + description: "StatusCode is the HTTP status code to + be used in response. \n Note that values may be + added to this enum, implementations must ensure + that unknown values will not cause a crash. \n Unknown + values here must result in the implementation setting + the Accepted Condition for the Route to `status: + False`, with a Reason of `UnsupportedValue`. \n + Support: Core" + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: "ResponseHeaderModifier defines a schema + for a filter that modifies response headers. \n 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. \n Input: GET /foo HTTP/1.1 my-header: foo + \n Config: add: - name: \"my-header\" value: \"bar,baz\" + \n 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). + \n 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). + \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: + bar my-header3: baz \n Config: remove: [\"my-header1\", + \"my-header3\"] \n 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. \n + Input: GET /foo HTTP/1.1 my-header: foo \n Config: + set: - name: \"my-header\" value: \"bar\" \n 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). + \n 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: \n - Core: Filter types and + their corresponding configuration defined by \"Support: + Core\" in this package, e.g. \"RequestHeaderModifier\". + All implementations must support core filters. \n - + Extended: Filter types and their corresponding configuration + defined by \"Support: Extended\" in this package, e.g. + \"RequestMirror\". Implementers are encouraged to support + extended filters. \n - 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. \n Implementers are encouraged to + define custom implementation types to extend the core + API with implementation-specific behavior. \n 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. \n Note that values may be added to this enum, + implementations must ensure that unknown values will + not cause a crash. \n 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. \n Support: + Extended" + properties: + hostname: + description: "Hostname is the value to be used to + replace the Host header value during forwarding. + \n 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. \n 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\". + \n 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. \n 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`. \n Request Path | Prefix + Match | Replace Prefix | Modified Path -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | + /xyz/bar /foo/bar | /foo | /xyz/ + \ | /xyz/bar /foo/bar | /foo/ | + /xyz | /xyz/bar /foo/bar | /foo/ + \ | /xyz/ | /xyz/bar /foo | + /foo | /xyz | /xyz /foo/ | + /foo | /xyz | /xyz/ /foo/bar + \ | /foo | | /bar + /foo/ | /foo | + | / /foo | /foo | + | / /foo/ | /foo | / | + / /foo | /foo | / | + /" + 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. \n Note that values may be added + to this enum, implementations must ensure that + unknown values will not cause a crash. \n 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. \n For example, take the following matches configuration: + \n ``` matches: - path: value: \"/foo\" headers: - name: \"version\" + value: \"v2\" - path: value: \"/v2/foo\" ``` \n For a request + to match against this rule, a request must satisfy EITHER + of the two conditions: \n - path prefixed with `/foo` AND + contains the header `version: v2` - path prefix of `/v2/foo` + \n See the documentation for HTTPRouteMatch on how to specify + multiple match conditions that should be ANDed together. \n + If no matches are specified, the default is a prefix path + match on \"/\", which has the effect of matching every HTTP + request. \n 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: + \n * \"Exact\" path match. * \"Prefix\" path match with largest + number of characters. * Method match. * Largest number of + header matches. * Largest number of query param matches. \n + Note: The precedence of RegularExpression path matches are + implementation-specific. \n If ties still exist across multiple + Routes, matching precedence MUST be determined in order of + the following criteria, continuing on ties: \n * The oldest + Route based on creation timestamp. * The Route appearing first + in alphabetical order by \"{namespace}/{name}\". \n 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. \n 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 action. Multiple match types are + ANDed together, i.e. the match will evaluate to true only + if all conditions are satisfied. \n For example, the match + below will match a HTTP request only if its path starts + with `/foo` AND it contains the `version: v1` header: \n + ``` match: \n path: value: \"/foo\" headers: - name: \"version\" + value \"v1\" \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). + \n 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. + \n 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. \n Support: Core (Exact) + \n Support: Implementation-specific (RegularExpression) + \n 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. \n 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. \n Support: Core (Exact, PathPrefix) + \n 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. \n 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). + \n 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. \n 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. + \n 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. \n Support: + Extended (Exact) \n Support: Implementation-specific + (RegularExpression) \n 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: 8 + type: array + 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 + 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. + \n 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. \n 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. \n 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. \n A Route MUST be considered \"Accepted\" + if at least one of the Route's rules is implemented by the + Gateway. \n There are a number of cases where the \"Accepted\" + condition may not be set due to lack of controller visibility, + that includes when: \n * 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. --- This struct + is intended for direct use as an array at the field path + .status.conditions. For example, \n type FooStatus struct{ + // Represents the observations of a foo's current state. + // Known .status.conditions.type are: \"Available\", \"Progressing\", + and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields + }" + 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. + --- Many .condition.type values are consistent across + resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability + to deconflict is important. The regex it matches is + (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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. \n Example: + \"example.net/gateway-controller\". \n 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). + \n 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). \n + 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. \n There are + two kinds of parent resources with \"Core\" support: \n + * Gateway (Gateway conformance profile) * Service (Mesh + conformance profile, experimental, ClusterIP Services + only) \n 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. \n 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. \n 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. \n \n Support: Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + sectionName: + description: "SectionName is the name of a section within + the target resource. In the following resources, SectionName + is interpreted as the following: \n * 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. Note that attaching Routes to Services + as Parents is part of experimental Mesh support and is + not supported for any other purpose. \n Implementations + MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName + is interpreted. \n 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. + \n 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: {} + - 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. \n Valid values for Hostnames + are determined by RFC 1123 definition of a hostname with 2 notable + exceptions: \n 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. \n 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: + \n * 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. \n 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`. \n 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. \n 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. \n 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: \n * Characters in a matching + non-wildcard hostname. * Characters in a matching hostname. \n If + ties exist across multiple Routes, the matching precedence rules + for HTTPRouteMatches takes over. \n 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: \n 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. \n 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`). + \n 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. \n There are two kinds of parent resources with \"Core\" + support: \n * Gateway (Gateway conformance profile) This API may + be extended in the future to support additional kinds of parent + resources. \n ParentRefs must be _distinct_. This means either that: + \n * 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. \n Some examples: + \n * 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`. \n 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. \n 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. \n \n " + 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: \n * Gateway (Gateway conformance profile) * Service + (Mesh conformance profile, experimental, ClusterIP Services only) + \n This API may be extended in the future to support additional + kinds of parent resources. \n 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). \n 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. \n There are two + kinds of parent resources with \"Core\" support: \n * Gateway + (Gateway conformance profile) * Service (Mesh conformance + profile, experimental, ClusterIP Services only) \n 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. \n 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. + \n 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. + \n \n Support: Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + sectionName: + description: "SectionName is the name of a section within the + target resource. In the following resources, SectionName is + interpreted as the following: \n * 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. Note that attaching + Routes to Services as Parents is part of experimental Mesh + support and is not supported for any other purpose. \n Implementations + MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName + is interpreted. \n 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. \n 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. \n Failure behavior here depends + on how many BackendRefs are specified and how many are invalid. + \n 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. \n + See the HTTPBackendRef definition for the rules about what + makes a single HTTPBackendRef invalid. \n 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. + \n 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. + \n Support: Core for Kubernetes Service \n Support: Extended + for Kubernetes ServiceImport \n Support: Implementation-specific + for any other resource \n Support for weight: Core" + items: + description: "HTTPBackendRef defines how a HTTPRoute forwards + a HTTP request. \n 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. \n + \n When the BackendRef points to a Kubernetes Service, implementations + SHOULD honor the appProtocol field if it is set for the + target Service Port. \n Implementations supporting appProtocol + SHOULD recognize the Kubernetes Standard Application Protocols + defined in KEP-3726. \n 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. \n 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. \n + " + 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. \n 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. \n This filter can be used multiple times + within the same rule. \n 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. \n + 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. \n Input: GET /foo HTTP/1.1 + my-header: foo \n Config: add: - name: \"my-header\" + value: \"bar,baz\" \n 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). + \n 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). + \n Input: GET /foo HTTP/1.1 my-header1: foo + my-header2: bar my-header3: baz \n Config: + remove: [\"my-header1\", \"my-header3\"] \n + 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. \n Input: GET /foo HTTP/1.1 my-header: + foo \n Config: set: - name: \"my-header\" + value: \"bar\" \n 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). + \n 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. \n 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. \n Support: Extended" + properties: + backendRef: + description: "BackendRef references a resource + where mirrored requests are sent. \n Mirrored + requests must be sent only to a single destination + endpoint within this BackendRef, irrespective + of how many endpoints are present within this + BackendRef. \n 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. + \n 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. \n In either error + case, the Message of the `ResolvedRefs` Condition + should be used to provide more detail about + the problem. \n Support: Extended for Kubernetes + Service \n 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\". + \n Defaults to \"Service\" when not specified. + \n 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. \n Support: Core (Services with + a type other than ExternalName) \n 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. \n 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. \n 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. \n 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. + \n 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. \n 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\". \n 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. + \n 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`. \n Request Path + | Prefix Match | Replace Prefix | Modified + Path -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | + /xyz/bar /foo/bar | /foo | + /xyz/ | /xyz/bar /foo/bar | + /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | + /xyz/bar /foo | /foo | + /xyz | /xyz /foo/ | /foo + \ | /xyz | /xyz/ /foo/bar + \ | /foo | | + /bar /foo/ | /foo | | / /foo | /foo | + | / /foo/ | /foo + \ | / | / /foo | + /foo | / | /" + 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. \n Note + that values may be added to this enum, + implementations must ensure that unknown + values will not cause a crash. \n 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. \n If no port is specified, the + redirect port MUST be derived using the following + rules: \n * 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. \n Implementations SHOULD NOT + add the port number in the 'Location' header + in the following cases: \n * 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. \n 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. \n Scheme redirects can affect the + port of the redirect, for more information, + refer to the documentation for the port field + of this filter. \n Note that values may be + added to this enum, implementations must ensure + that unknown values will not cause a crash. + \n Unknown values here must result in the + implementation setting the Accepted Condition + for the Route to `status: False`, with a Reason + of `UnsupportedValue`. \n Support: Extended" + enum: + - http + - https + type: string + statusCode: + default: 302 + description: "StatusCode is the HTTP status + code to be used in response. \n Note that + values may be added to this enum, implementations + must ensure that unknown values will not cause + a crash. \n Unknown values here must result + in the implementation setting the Accepted + Condition for the Route to `status: False`, + with a Reason of `UnsupportedValue`. \n Support: + Core" + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: "ResponseHeaderModifier defines a schema + for a filter that modifies response headers. \n + 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. \n Input: GET /foo HTTP/1.1 + my-header: foo \n Config: add: - name: \"my-header\" + value: \"bar,baz\" \n 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). + \n 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). + \n Input: GET /foo HTTP/1.1 my-header1: foo + my-header2: bar my-header3: baz \n Config: + remove: [\"my-header1\", \"my-header3\"] \n + 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. \n Input: GET /foo HTTP/1.1 my-header: + foo \n Config: set: - name: \"my-header\" + value: \"bar\" \n 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). + \n 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: \n - + Core: Filter types and their corresponding configuration + defined by \"Support: Core\" in this package, + e.g. \"RequestHeaderModifier\". All implementations + must support core filters. \n - Extended: Filter + types and their corresponding configuration defined + by \"Support: Extended\" in this package, e.g. + \"RequestMirror\". Implementers are encouraged + to support extended filters. \n - 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. \n Implementers are encouraged + to define custom implementation types to extend + the core API with implementation-specific behavior. + \n 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. \n + Note that values may be added to this enum, implementations + must ensure that unknown values will not cause + a crash. \n 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. + \n Support: Extended" + properties: + hostname: + description: "Hostname is the value to be used + to replace the Host header value during forwarding. + \n 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. \n + 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\". \n 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. + \n 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`. \n Request Path + | Prefix Match | Replace Prefix | Modified + Path -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | + /xyz/bar /foo/bar | /foo | + /xyz/ | /xyz/bar /foo/bar | + /foo/ | /xyz | /xyz/bar + /foo/bar | /foo/ | /xyz/ | + /xyz/bar /foo | /foo | + /xyz | /xyz /foo/ | /foo + \ | /xyz | /xyz/ /foo/bar + \ | /foo | | + /bar /foo/ | /foo | | / /foo | /foo | + | / /foo/ | /foo + \ | / | / /foo | + /foo | / | /" + 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. \n Note + that values may be added to this enum, + implementations must ensure that unknown + values will not cause a crash. \n 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\". \n Defaults to + \"Service\" when not specified. \n 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. + \n Support: Core (Services with a type other than ExternalName) + \n 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. \n + 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. \n 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. \n + 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. \n 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. \n The effects of ordering + of multiple behaviors are currently unspecified. This can + change in the future based on feedback during the alpha stage. + \n Conformance-levels at this level are defined based on the + type of filter: \n - 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. \n Specifying + the same filter multiple times is not supported unless explicitly + indicated in the filter. \n 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. \n 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. \n This filter can be used multiple times within + the same rule. \n 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. \n 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. \n Input: GET /foo HTTP/1.1 my-header: foo + \n Config: add: - name: \"my-header\" value: \"bar,baz\" + \n 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). + \n 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). + \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: + bar my-header3: baz \n Config: remove: [\"my-header1\", + \"my-header3\"] \n 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. \n + Input: GET /foo HTTP/1.1 my-header: foo \n Config: + set: - name: \"my-header\" value: \"bar\" \n 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). + \n 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. \n 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. \n + Support: Extended" + properties: + backendRef: + description: "BackendRef references a resource where + mirrored requests are sent. \n Mirrored requests + must be sent only to a single destination endpoint + within this BackendRef, irrespective of how many + endpoints are present within this BackendRef. \n + 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. \n 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. \n In either error case, the Message + of the `ResolvedRefs` Condition should be used to + provide more detail about the problem. \n Support: + Extended for Kubernetes Service \n 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\". + \n Defaults to \"Service\" when not specified. + \n 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. \n Support: Core (Services with a + type other than ExternalName) \n 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. \n 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. \n 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. + \n 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. \n 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. \n 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\". + \n 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. \n 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`. \n Request Path | Prefix + Match | Replace Prefix | Modified Path -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | + /xyz/bar /foo/bar | /foo | /xyz/ + \ | /xyz/bar /foo/bar | /foo/ | + /xyz | /xyz/bar /foo/bar | /foo/ + \ | /xyz/ | /xyz/bar /foo | + /foo | /xyz | /xyz /foo/ | + /foo | /xyz | /xyz/ /foo/bar + \ | /foo | | /bar + /foo/ | /foo | + | / /foo | /foo | + | / /foo/ | /foo | / | + / /foo | /foo | / | + /" + 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. \n Note that values may be added + to this enum, implementations must ensure that + unknown values will not cause a crash. \n 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. \n If + no port is specified, the redirect port MUST be + derived using the following rules: \n * 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. + \n Implementations SHOULD NOT add the port number + in the 'Location' header in the following cases: + \n * 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. \n 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. \n + Scheme redirects can affect the port of the redirect, + for more information, refer to the documentation + for the port field of this filter. \n Note that + values may be added to this enum, implementations + must ensure that unknown values will not cause a + crash. \n Unknown values here must result in the + implementation setting the Accepted Condition for + the Route to `status: False`, with a Reason of `UnsupportedValue`. + \n Support: Extended" + enum: + - http + - https + type: string + statusCode: + default: 302 + description: "StatusCode is the HTTP status code to + be used in response. \n Note that values may be + added to this enum, implementations must ensure + that unknown values will not cause a crash. \n Unknown + values here must result in the implementation setting + the Accepted Condition for the Route to `status: + False`, with a Reason of `UnsupportedValue`. \n + Support: Core" + enum: + - 301 + - 302 + type: integer + type: object + responseHeaderModifier: + description: "ResponseHeaderModifier defines a schema + for a filter that modifies response headers. \n 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. \n Input: GET /foo HTTP/1.1 my-header: foo + \n Config: add: - name: \"my-header\" value: \"bar,baz\" + \n 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). + \n 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). + \n Input: GET /foo HTTP/1.1 my-header1: foo my-header2: + bar my-header3: baz \n Config: remove: [\"my-header1\", + \"my-header3\"] \n 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. \n + Input: GET /foo HTTP/1.1 my-header: foo \n Config: + set: - name: \"my-header\" value: \"bar\" \n 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). + \n 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: \n - Core: Filter types and + their corresponding configuration defined by \"Support: + Core\" in this package, e.g. \"RequestHeaderModifier\". + All implementations must support core filters. \n - + Extended: Filter types and their corresponding configuration + defined by \"Support: Extended\" in this package, e.g. + \"RequestMirror\". Implementers are encouraged to support + extended filters. \n - 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. \n Implementers are encouraged to + define custom implementation types to extend the core + API with implementation-specific behavior. \n 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. \n Note that values may be added to this enum, + implementations must ensure that unknown values will + not cause a crash. \n 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. \n Support: + Extended" + properties: + hostname: + description: "Hostname is the value to be used to + replace the Host header value during forwarding. + \n 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. \n 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\". + \n 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. \n 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`. \n Request Path | Prefix + Match | Replace Prefix | Modified Path -------------|--------------|----------------|---------- + /foo/bar | /foo | /xyz | + /xyz/bar /foo/bar | /foo | /xyz/ + \ | /xyz/bar /foo/bar | /foo/ | + /xyz | /xyz/bar /foo/bar | /foo/ + \ | /xyz/ | /xyz/bar /foo | + /foo | /xyz | /xyz /foo/ | + /foo | /xyz | /xyz/ /foo/bar + \ | /foo | | /bar + /foo/ | /foo | + | / /foo | /foo | + | / /foo/ | /foo | / | + / /foo | /foo | / | + /" + 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. \n Note that values may be added + to this enum, implementations must ensure that + unknown values will not cause a crash. \n 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. \n For example, take the following matches configuration: + \n ``` matches: - path: value: \"/foo\" headers: - name: \"version\" + value: \"v2\" - path: value: \"/v2/foo\" ``` \n For a request + to match against this rule, a request must satisfy EITHER + of the two conditions: \n - path prefixed with `/foo` AND + contains the header `version: v2` - path prefix of `/v2/foo` + \n See the documentation for HTTPRouteMatch on how to specify + multiple match conditions that should be ANDed together. \n + If no matches are specified, the default is a prefix path + match on \"/\", which has the effect of matching every HTTP + request. \n 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: + \n * \"Exact\" path match. * \"Prefix\" path match with largest + number of characters. * Method match. * Largest number of + header matches. * Largest number of query param matches. \n + Note: The precedence of RegularExpression path matches are + implementation-specific. \n If ties still exist across multiple + Routes, matching precedence MUST be determined in order of + the following criteria, continuing on ties: \n * The oldest + Route based on creation timestamp. * The Route appearing first + in alphabetical order by \"{namespace}/{name}\". \n 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. \n 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 action. Multiple match types are + ANDed together, i.e. the match will evaluate to true only + if all conditions are satisfied. \n For example, the match + below will match a HTTP request only if its path starts + with `/foo` AND it contains the `version: v1` header: \n + ``` match: \n path: value: \"/foo\" headers: - name: \"version\" + value \"v1\" \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). + \n 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. + \n 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. \n Support: Core (Exact) + \n Support: Implementation-specific (RegularExpression) + \n 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. \n 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. \n Support: Core (Exact, PathPrefix) + \n 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. \n 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). + \n 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. \n 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. + \n 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. \n Support: + Extended (Exact) \n Support: Implementation-specific + (RegularExpression) \n 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: 8 + type: array + 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 + 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. + \n 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. \n 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. \n 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. \n A Route MUST be considered \"Accepted\" + if at least one of the Route's rules is implemented by the + Gateway. \n There are a number of cases where the \"Accepted\" + condition may not be set due to lack of controller visibility, + that includes when: \n * 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. --- This struct + is intended for direct use as an array at the field path + .status.conditions. For example, \n type FooStatus struct{ + // Represents the observations of a foo's current state. + // Known .status.conditions.type are: \"Available\", \"Progressing\", + and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields + }" + 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. + --- Many .condition.type values are consistent across + resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability + to deconflict is important. The regex it matches is + (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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. \n Example: + \"example.net/gateway-controller\". \n 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). + \n 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). \n + 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. \n There are + two kinds of parent resources with \"Core\" support: \n + * Gateway (Gateway conformance profile) * Service (Mesh + conformance profile, experimental, ClusterIP Services + only) \n 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. \n 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. \n 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. \n \n Support: Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + sectionName: + description: "SectionName is the name of a section within + the target resource. In the following resources, SectionName + is interpreted as the following: \n * 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. Note that attaching Routes to Services + as Parents is part of experimental Mesh support and is + not supported for any other purpose. \n Implementations + MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName + is interpreted. \n 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. + \n 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: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/2466 + gateway.networking.k8s.io/bundle-version: v1.0.0 + 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 + deprecated: true + deprecationWarning: The v1alpha2 version of ReferenceGrant has been deprecated + and will be removed in a future release of the API. Please upgrade to v1beta1. + name: v1alpha2 + 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. \n 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. \n A ReferenceGrant is required for all cross-namespace + references in Gateway API (with the exception of cross-namespace Route-Gateway + attachment, which is governed by the AllowedRoutes configuration on the + Gateway, and cross-namespace Service ParentRefs on a \"consumer\" mesh Route, + which defines routing rules applicable only to workloads in the Route namespace). + ReferenceGrants allowing a reference from a Route to a Service are only + applicable to BackendRefs. \n 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. \n 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. \n 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. \n When + used to permit a SecretObjectReference: \n * Gateway \n When + used to permit a BackendObjectReference: \n * 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. \n + 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. + \n 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. \n 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: \n * 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: false + subresources: {} + - 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. \n 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. \n All cross-namespace references in Gateway API + (with the exception of cross-namespace Gateway-route attachment) require + a ReferenceGrant. \n 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. \n 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. \n 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. \n When + used to permit a SecretObjectReference: \n * Gateway \n When + used to permit a BackendObjectReference: \n * 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. \n + 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. + \n 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. \n 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: \n * 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/kong2kic/testdata/global-plugin-input.yaml b/kong2kic/testdata/global-plugin-input.yaml new file mode 100644 index 000000000..d12209c0e --- /dev/null +++ b/kong2kic/testdata/global-plugin-input.yaml @@ -0,0 +1,12 @@ +plugins: +- name: prometheus + enabled: true + config: + per_consumer: true + status_code_metrics: true + latency_metrics: true + bandwidth_metrics: true + upstream_health_metrics: true + tags: + - cloudops-managed + - metrics \ No newline at end of file diff --git a/kong2kic/testdata/global-plugin-output-expected.yaml b/kong2kic/testdata/global-plugin-output-expected.yaml new file mode 100644 index 000000000..2ecdc5fb1 --- /dev/null +++ b/kong2kic/testdata/global-plugin-output-expected.yaml @@ -0,0 +1,15 @@ +apiVersion: configuration.konghq.com/v1 +config: + bandwidth_metrics: true + latency_metrics: true + per_consumer: true + status_code_metrics: true + upstream_health_metrics: true +kind: KongClusterPlugin +metadata: + annotations: + konghq.com/tags: cloudops-managed,metrics + kubernetes.io/ingress.class: kong + name: prometheus +plugin: prometheus +--- \ No newline at end of file diff --git a/kong2kic/testdata/kicv2_gateway/output-expected.json b/kong2kic/testdata/kicv2_gateway/output-expected.json deleted file mode 100644 index f18d118f2..000000000 --- a/kong2kic/testdata/kicv2_gateway/output-expected.json +++ /dev/null @@ -1,1483 +0,0 @@ -{ - "apiVersion": "configuration.konghq.com/v1", - "kind": "KongIngress", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service-upstream" - }, - "upstream": { - "algorithm": "round-robin", - "hash_fallback": "none", - "hash_on": "none", - "hash_on_cookie_path": "/", - "healthchecks": { - "active": { - "concurrency": 10, - "headers": { - "x-another-header": [ - "bla" - ], - "x-my-header": [ - "foo", - "bar" - ] - }, - "healthy": { - "http_statuses": [ - 200, - 302 - ], - "interval": 0, - "successes": 0 - }, - "http_path": "/", - "https_sni": "example.com", - "https_verify_certificate": true, - "timeout": 1, - "type": "http", - "unhealthy": { - "http_failures": 0, - "http_statuses": [ - 429, - 404, - 500, - 501, - 502, - 503, - 504, - 505 - ], - "interval": 0, - "tcp_failures": 0, - "timeouts": 0 - } - }, - "passive": { - "healthy": { - "http_statuses": [ - 200, - 201, - 202, - 203, - 204, - 205, - 206, - 207, - 208, - 226, - 300, - 301, - 302, - 303, - 304, - 305, - 306, - 307, - 308 - ], - "successes": 0 - }, - "type": "http", - "unhealthy": { - "http_failures": 0, - "http_statuses": [ - 429, - 500, - 503 - ], - "tcp_failures": 0, - "timeouts": 0 - } - }, - "threshold": 0 - }, - "host_header": "example.com", - "slots": 10000 - } -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_client_headers": false, - "identifier": "consumer", - "limit": [ - 5 - ], - "namespace": "example_namespace", - "strategy": "local", - "sync_rate": -1, - "window_size": [ - 30 - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service-rate-limiting-advanced" - }, - "plugin": "rate-limiting-advanced" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "aws_key": "my_key", - "aws_region": "us-west-2", - "aws_secret": "my_secret", - "function_name": "my_function" - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "plugin": "aws-lambda" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "credentials": true, - "exposed_headers": [ - "X-My-Header" - ], - "headers": [ - "Authorization" - ], - "max_age": 3600, - "methods": [ - "GET", - "POST" - ], - "origins": [ - "example.com" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "plugin": "cors" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "path": "/var/log/kong/kong.log", - "reopen": true - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "plugin": "file-log" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "content_type": "application/json", - "http_endpoint": "http://example.com/logs", - "keepalive": 60000, - "method": "POST", - "queue_size": 1000, - "retry_count": 10, - "timeout": 10000 - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "plugin": "http-log" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "allow": [ - "192.168.0.1/24" - ], - "deny": [ - "192.168.0.2/32" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "plugin": "ip-restriction" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_client_headers": false, - "identifier": "consumer", - "limit": [ - 5 - ], - "namespace": "example_namespace", - "strategy": "local", - "sync_rate": -1, - "window_size": [ - 30 - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "plugin": "rate-limiting-advanced" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "message": "Forbidden", - "status_code": 403 - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "plugin": "request-termination" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "limits": { - "limit_name": { - "minute": 10 - } - }, - "policy": "local" - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "plugin": "response-ratelimiting" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "host": "example.com", - "port": 1234 - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "plugin": "tcp-log" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_credentials": false - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "plugin": "basic-auth" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "anonymous": null, - "claims_to_verify": [ - "exp", - "nbf" - ], - "header_names": [ - "Authorization" - ], - "key_claim_name": "kid", - "maximum_expiration": 3600, - "run_on_preflight": true, - "secret_is_base64": false, - "uri_param_names": [ - "token" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "plugin": "jwt" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_credentials": false, - "key_in_body": false, - "key_names": [ - "apikey" - ], - "run_on_preflight": true - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "plugin": "key-auth" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "ca_certificates": [ - "cce8c384-721f-4f58-85dd-50834e3e733a" - ], - "revocation_check_mode": "SKIP", - "skip_consumer_lookup": false - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "plugin": "mtls-auth" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "allow": [ - "admin" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "plugin": "acl" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_client_headers": false, - "identifier": "consumer", - "limit": [ - 5 - ], - "namespace": "example_namespace", - "strategy": "local", - "sync_rate": -1, - "window_size": [ - 30 - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-user-rate-limiting-advanced" - }, - "plugin": "rate-limiting-advanced" -}{ - "apiVersion": "gateway.networking.k8s.io/v1beta1", - "kind": "HTTPRoute", - "metadata": { - "annotations": { - "konghq.com/https-redirect-status-code": "302", - "konghq.com/preserve-host": "true", - "konghq.com/regex-priority": "1", - "konghq.com/snis": "example.com", - "konghq.com/strip-path": "false" - }, - "name": "example-service--route-thisisaveryvery-long2093a020ca" - }, - "spec": { - "hostnames": [ - "example.com", - "another-example.com", - "yet-another-example.com" - ], - "parentRefs": [ - { - "name": "kong" - } - ], - "rules": [ - { - "backendRefs": [ - { - "name": "example-service", - "port": 80 - } - ], - "filters": [ - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "type": "ExtensionRef" - } - ], - "matches": [ - { - "headers": [ - { - "name": "x-another-header", - "type": "Exact", - "value": "first-header-value,second-header-value" - }, - { - "name": "x-my-header", - "type": "RegularExpression", - "value": "foos?bar$" - } - ], - "method": "GET", - "path": { - "type": "RegularExpression", - "value": "/v1/example/?$" - } - } - ] - }, - { - "backendRefs": [ - { - "name": "example-service", - "port": 80 - } - ], - "filters": [ - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "type": "ExtensionRef" - } - ], - "matches": [ - { - "headers": [ - { - "name": "x-another-header", - "type": "Exact", - "value": "first-header-value,second-header-value" - }, - { - "name": "x-my-header", - "type": "RegularExpression", - "value": "foos?bar$" - } - ], - "method": "POST", - "path": { - "type": "RegularExpression", - "value": "/v1/example/?$" - } - } - ] - }, - { - "backendRefs": [ - { - "name": "example-service", - "port": 80 - } - ], - "filters": [ - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "type": "ExtensionRef" - } - ], - "matches": [ - { - "headers": [ - { - "name": "x-another-header", - "type": "Exact", - "value": "first-header-value,second-header-value" - }, - { - "name": "x-my-header", - "type": "RegularExpression", - "value": "foos?bar$" - } - ], - "method": "GET", - "path": { - "type": "PathPrefix", - "value": "/v1/another-example" - } - } - ] - }, - { - "backendRefs": [ - { - "name": "example-service", - "port": 80 - } - ], - "filters": [ - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "type": "ExtensionRef" - } - ], - "matches": [ - { - "headers": [ - { - "name": "x-another-header", - "type": "Exact", - "value": "first-header-value,second-header-value" - }, - { - "name": "x-my-header", - "type": "RegularExpression", - "value": "foos?bar$" - } - ], - "method": "POST", - "path": { - "type": "PathPrefix", - "value": "/v1/another-example" - } - } - ] - }, - { - "backendRefs": [ - { - "name": "example-service", - "port": 80 - } - ], - "filters": [ - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "type": "ExtensionRef" - } - ], - "matches": [ - { - "headers": [ - { - "name": "x-another-header", - "type": "Exact", - "value": "first-header-value,second-header-value" - }, - { - "name": "x-my-header", - "type": "RegularExpression", - "value": "foos?bar$" - } - ], - "method": "GET", - "path": { - "type": "PathPrefix", - "value": "/v1/yet-another-example" - } - } - ] - }, - { - "backendRefs": [ - { - "name": "example-service", - "port": 80 - } - ], - "filters": [ - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "type": "ExtensionRef" - } - ], - "matches": [ - { - "headers": [ - { - "name": "x-another-header", - "type": "Exact", - "value": "first-header-value,second-header-value" - }, - { - "name": "x-my-header", - "type": "RegularExpression", - "value": "foos?bar$" - } - ], - "method": "POST", - "path": { - "type": "PathPrefix", - "value": "/v1/yet-another-example" - } - } - ] - } - ] - } -}{ - "apiVersion": "v1", - "kind": "Service", - "metadata": { - "annotations": { - "konghq.com/connect-timeout": "5000", - "konghq.com/override": "example-service-upstream", - "konghq.com/path": "/v1", - "konghq.com/plugins": "example-service-rate-limiting-advanced", - "konghq.com/protocol": "http", - "konghq.com/read-timeout": "60000", - "konghq.com/retries": "5", - "konghq.com/write-timeout": "60000" - }, - "name": "example-service" - }, - "spec": { - "ports": [ - { - "port": 80, - "protocol": "TCP", - "targetPort": 80 - } - ], - "selector": { - "app": "example-service" - } - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "key-auth-example-user" - }, - "stringData": { - "key": "my_api_key", - "kongCredType": "key-auth" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "jwt-auth-example-user" - }, - "stringData": { - "algorithm": "HS256", - "key": "my_jwt_secret", - "kongCredType": "jwt", - "rsa_public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxXzYS5yESbekTF3xLiQX\nZZZfXt0S/nzFp3f2Oux3W7/ydvZ8XSd8+s+wm5oqEcSV9n+5n3ENZbt1A/wgnGI3\noWrv0yRB9HugzTIGPpI1AQv9Z4p8E44RrB74/uTxYwb9+4yvpuz/fzTt3Gz+Kzc4\n4fGGq8VpGMFj6AE65ZcOAHHUJe4VuoreBXLYDJcHl2WPIdNKDGscFjElDneLRhWQ\nDfxekDJIQMWCjyBEXacfP6cc9U8Qld6TuVcwi1P2xb8tBDD4MIFL/psfzUhfv1Lw\nO/XZEffJxCqkQn7dsCYy3wpaTjb6XmJ5j0Dbml4f0Bv40Y1mjlAf7C662Mbuguf6\newIDAQAB\n-----END PUBLIC KEY-----", - "secret": "my_secret_key" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "basic-auth-example-user" - }, - "stringData": { - "kongCredType": "basic-auth", - "password": "my_basic_password", - "username": "my_basic_user" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "acl-group-example-user" - }, - "stringData": { - "group": "acl_group", - "kongCredType": "acl" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "mtls-auth-example-user" - }, - "stringData": { - "id": "cce8c384-721f-4f58-85dd-50834e3e733a", - "kongCredType": "mtls-auth", - "subject_name": "example-user@example.com" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "ca-cert-a672ab52d2341203bd70116b456413d7ac3ffc162abbf" - }, - "stringData": { - "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIBfDCCASKgAwIBAgIRAJqcZC1VSvSQLMN1+7yAeswwCgYIKoZIzj0EAwIwHDEa\nMBgGA1UEAxMRRGVtbyBLb25nIFJvb3QgQ0EwHhcNMjIwNjEzMTMzNzMzWhcNMjcw\nNjEzMTkzNzMzWjAcMRowGAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTBZMBMGByqG\nSM49AgEGCCqGSM49AwEHA0IABOGR89IyhreSHRAi6wp9a5DBIDp4YYSdWzuEdlNx\n7pX1G4T7x68xUXJZXRUPFyT8Xzn5KwCJm8RVT+nAhrsUx6SjRTBDMA4GA1UdDwEB\n/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBQ9CUiOPhjp7KD2\nScRDxX4IzDOrNzAKBggqhkjOPQQDAgNIADBFAiEAw6Dov0c0L++1W9VufAfSMdNR\nPSDfPU0MiUiG59/VIBICIEFn/6c5eQc3hUUBL74/RmNT2b1zxBmp7RiPXJAnAAwJ\n-----END CERTIFICATE-----\n", - "ca.digest": "f1baffe9fe9cf8497e38a4271d67fab44423678b7e7c0f677a50f37c113d81b5" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "ca-cert-a4f087c2ee00e6d43cfb4f6884fc1e79f7e6e08e84471" - }, - "stringData": { - "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIBqTCCAVCgAwIBAgIQb5LqGa9gS3+Mc2ntWfSoJjAKBggqhkjOPQQDAjAcMRow\nGAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTAeFw0yMjA2MTMxMzM5MTVaFw0yMzA2\nMTMxOTM5MTVaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBSb290IEludGVybWVkaWF0\nZTEgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQImvnSuvXkGy88lvx8a7of\ne0MEMRI2siVvybvWXNpeXXlixgaq7weJ7pewf3HywfO68Va6kn8ehWh7s0D7SLHM\no2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4E\nFgQUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwHwYDVR0jBBgwFoAUPQlIjj4Y6eyg9knE\nQ8V+CMwzqzcwCgYIKoZIzj0EAwIDRwAwRAIgNZ+JPA1OqF5DsPapAZ2YsUOgIpn3\nZbQuYKCAV0SD4EcCIFnfA5rWrc1AgtUw5inJQqJQRNgoPuC14vACqI48BiRl\n-----END CERTIFICATE-----\n", - "ca.digest": "dbef7ed285fb292e24f84ffba93c48d92fa322387d85469c460c655abedd5308" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "ca-cert-6b095c7ff377b01252a4dfec59c582fe32934fa7ed0cf" - }, - "stringData": { - "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIBujCCAV+gAwIBAgIRAMkGpj7WZf+2RFE/q7ZhejEwCgYIKoZIzj0EAwIwKjEo\nMCYGA1UEAxMfRGVtbyBLb25nIFJvb3QgSW50ZXJtZWRpYXRlMSBDQTAeFw0yMjA2\nMTMxMzQwNTFaFw0yMjEyMTMwNDQwNTFaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBS\nb290IEludGVybWVkaWF0ZTIgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQB\nmy/zhZ3F2HvHFqtQzuD3lXX8SeYakxiBQvaGkGSLKD67N3vh7iC2rTSdj/vAs8ws\nY9X+mXzS6GDKC8PbSX6xo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgw\nBgEB/wIBADAdBgNVHQ4EFgQURwCm53YPStZoAMfnVyknH4IgZa4wHwYDVR0jBBgw\nFoAUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwCgYIKoZIzj0EAwIDSQAwRgIhAN1pkUKc\nazM4PiXOnkILB2KBDIF4XpHf+4ThDMODzXP8AiEA45KXA3qMrRPQV1oBfWZ3hLgX\ngxUhveuHBXMWnzUbn6U=\n-----END CERTIFICATE-----\n", - "ca.digest": "45b2b6dd9d4102955b1b1e4b540e677f140521462ed4f22fa5a713863ca84600" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "cert-0ee0e1584c8637facac95bd5fce315367dee124c0086d41e" - }, - "stringData": { - "tls.crt": "-----BEGIN CERTIFICATE-----\nMIIECTCCAvGgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyAwDQYJKoZIhvcNAQEL\nBQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM\nCUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY\nMBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u\nZ2hxLmNvbTAeFw0yMTAxMTUxMTE5NDNaFw0yMjA1MzAxMTE5NDNaMIGRMQswCQYD\nVQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx\nEDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFzAVBgNVBAMMDnBy\nb3h5LmtvbmcubGFuMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29uZ2hxLmNvbTCCASIw\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJUbKiqoCK1BTNk/7l42n6ukyTEu\neLyB23e/90PzT/oz8wZzgwTodzbFAS2VtFr1EKqFzor0DrXp9CLnebOdiAR3I6LD\n/WY/x0KW3lx3F35fGiUOSLPTH8zeiDTMx11CcKDxesA+M2/s5q0igkOQ4z4w3voz\nm5a52IcQTSA8K5knNU1qUZBLpc+khxFcaheEK1jsISJJhcdizZBfGdk8S1vpyj5F\nuCZ7oaRvNA6imHjSJwpgo36zd84TgrIgVj9R4QtJysWy/X+bbaKUiKBWwAtd4+DT\nEP90l/ny9szu2fijk4/6k1ntXufGTyvM+J0/qJ13e99TVYOVanITnpTO+6cCAwEA\nAaNWMFQwHwYDVR0jBBgwFoAUdskpf0wJRQxjtzQFZciWmUfl2bcwCQYDVR0TBAIw\nADALBgNVHQ8EBAMCBPAwGQYDVR0RBBIwEIIOcHJveHkua29uZy5sYW4wDQYJKoZI\nhvcNAQELBQADggEBAJVrTWQRQzNtypa9OXFYADm8Fay1VMop3BY2kh0tfYgQEJ/4\npJUj6CaszQZ/Aix6LaPnXFcoPCDqqv00mgju86PMamr/zA9USXk8eTmzJkp5RklS\nGdqiXboqESiQVvaNz3kdW7wgNz4FwaGCzkEi/dcc2LdtzLpWizx+TlxMMqjonUUM\novZgZo+OlhWRsDVT/qy5SFtA0vlVNtdBr2egXb1H7J8UDC+fax/iKa7+fBUHZOO9\nFk9U8bxgfQ+jPIVVL8CfAtR68Sos7NpWH0S2emqZRnQvf0MSNdkTQKWn4qR9sckj\nEwxs5FbrMmgCOgwk1PtgRmdP3RME0HwK/B03saQ=\n-----END CERTIFICATE-----", - "tls.key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCVGyoqqAitQUzZ\nP+5eNp+rpMkxLni8gdt3v/dD80/6M/MGc4ME6Hc2xQEtlbRa9RCqhc6K9A616fQi\n53mznYgEdyOiw/1mP8dClt5cdxd+XxolDkiz0x/M3og0zMddQnCg8XrAPjNv7Oat\nIoJDkOM+MN76M5uWudiHEE0gPCuZJzVNalGQS6XPpIcRXGoXhCtY7CEiSYXHYs2Q\nXxnZPEtb6co+Rbgme6GkbzQOoph40icKYKN+s3fOE4KyIFY/UeELScrFsv1/m22i\nlIigVsALXePg0xD/dJf58vbM7tn4o5OP+pNZ7V7nxk8rzPidP6idd3vfU1WDlWpy\nE56UzvunAgMBAAECggEAcq7lHNAHdHLgT8yrY41x/AwPryNGO/9JNW7SGVKAdjoU\ntyaLZHAEmXynLk+R28/YFMA8H4Yd9m9OlrYhVjRZFM4p+5vxP/7YHPB7cPUsfcda\nDZxR8PX25JVYf/vtb16V0ERLnKd62qCEwC/lr2A2WHQwXJLrHeAtmZzBJYUCJ5Xj\nDv1ZhyFjknswaV0vGXe6njTI6CzMQDTGysoagpCCo7RWgzjLREg2BGWd2UQpY4AW\nnYAP4QNt82UMQbgIqsEMj64mzS9Q+o1P84J1naSP5sCI22LeFRp6iezZc+D8EH/5\nRNONGSNWl3g6bsvN1VywYwjWn+waD3XAjXUu+peUgQKBgQDDu1QP28oSMKivHdfo\nkQ1HrTNBRc9eWeAMZFuIbbPLN8rdEibpOm3DwTqithnahqS0NLOsBnXNtuLw1Qr/\nzmOzn0yDO5XG8dlKr9vqWeBLdcRydLJBZwqEzWf4JwwwgfK3rItRaIbnAxnGUTS5\nSrrhNfBAIGS9jx5X2kvLC7hFQQKBgQDDBIrpLTIjRDloWZcu03z9Bhb8jQCyGb5C\n4MYs+duCnQIdNq/+maPspJzbVmF4b6S1zIPweI3fMvMeqRTbuf+drpElst1buFTO\nP0UMMn4V+4qGIOOkIy5JIKwR8sJD9tNDUPtxuDEotTB9IyWx6pdmCFz5v/bggDCu\nreoqflL+5wKBgQCDvb+L2QS+j4/KJk0flRoaJ2K7SVCVEesyjA3r2uLMImZhvAkC\nrDgbLSDZSbZHFp8fR+WzILoD11gSf2Ki4PjMeqkWH3HlcP0vPwTHTO0h/UdXPmKI\nkOFMl7CmHyoeMCj9JZ60EaXTMYwUpq3VFY6JbTOjBeqoh/8FZMHlDaNewQKBgCHg\nECEg8KyflTlDFrfTlMp+3E9STuShBCOp18LIRBEUJOHeNgQLvCXHElgnURcSjZHm\nzKRgzIQQ3Zpd1Hm2fWhuglgCEeF0y4ZoBx5vRueaoh1aaTCBy/B39GvJt2UG4vu2\nfXbrf96KWrnh+RJGpbXbjgr0BXZJzisJmrt25gPRAoGBAI3c+INpQXwrE+LBzCPu\nLwIVvkm5NpeIlKQtDNrqG1QvUhqyZ2/Xitc4FyiccW7WHxkGKGZyj7GbmpqEOnyY\niVku0LSftZgycet2uMdp0HaVAgi5S6aVf5yN0U/8R5ToxcbuEfqwrBIyRgse8lx3\nNNSvLxPAempmiFPSk9AtobYV\n-----END PRIVATE KEY-----" - }, - "type": "kubernetes.io/tls" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "cert-b12464ec431576239dd9cc2545d528f6cbdbd988cf076323" - }, - "stringData": { - "tls.crt": "-----BEGIN CERTIFICATE-----\nMIIFeDCCBGCgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyQwDQYJKoZIhvcNAQEL\nBQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM\nCUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY\nMBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u\nZ2hxLmNvbTAeFw0yMTAxMjAxNTA0NDVaFw0yMjAxMjAxNTA0NDVaMIGQMQswCQYD\nVQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx\nEDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFjAUBgNVBAMMDW10\nbHMtY29uc3VtZXIxHTAbBgkqhkiG9w0BCQEWDnN0dUBrb25naHEuY29tMIICIjAN\nBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1/+83/YNiEVKYvcuVwYGve6afsg1\nBYCn1+E9Uwgh0uwAenT/DKB8NhqoVxc7cZ2HaTI146IGmFICmctlTWvLPLglHmTo\nbyOUV6tIJAjvzyEOpC458hLGgbv8mhGXJWPxBVu7Wy6Hapz2bk0cEscfL7PHKaRu\n3D6r8/zbhhWAqe4EIt+NVYT6baaYBs7bPZQXs/sluKI+DNYuDeaAmoSuCc4ein6z\n0xDqCSMmPebzjns03ttB29vWL3eYY9dvgoCd+CPhXT/C4CHtvKbH+hOQYDtVF6MO\n1mmABAQTQWMR/00+QI0xtvuXtEPurla5dA0TN6ddCTOOcILKx62z5oc3Kqr+nHHa\n71zNzARUVaZ2vy1pRVr0DZgB7KqcFXhy/oy8IpmxUR1ASBDZl6B6RKrdQwvgLgmn\n3M/roNLAU+3nz4itpt/zf+X0suwdthrflic1R68z1SlYbyoGARWkZ/pOl6kLNVK2\nOsqQuICaajnW7t1oDd7z1+3hm+uoryDwvG6f3T9ZvWjKXYcKg7b+BjbFdahbDywD\nPgnhSz9AaoVWhR+GHIPrjRClMpEkra/yGJFvH3UpXhgg9d0DrLZE51Z75a9SvnAj\nvdLuNhx4bJbwLBgNGsJMkupzBrw4iCfbKFcBbP8o0Xjtarj7T/mkWuQ1GjWqfyrD\n55NecBPNw5C9BR0CAwEAAaOBxTCBwjAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQE\nAwIFoDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgQ2xpZW50IENl\ncnRpZmljYXRlMB0GA1UdDgQWBBSV3F+eicU8SVT4LcDJ6eMzP0todzAfBgNVHSME\nGDAWgBR2ySl/TAlFDGO3NAVlyJaZR+XZtzAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0l\nBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4IBAQB5L0OZ\nWELG9Pw6Ol1BsZYgpLR4PGNBB9dKm/9dd+q+ohZVFCfXcjZ3YOU1vh/HHQrALRNY\nI58JxcVCOx/qIW2uA0iSCqIT0sNb9cJLxfZf7X+BzPPPnu0ugUJp7GzLNnHitrLC\nXb1nmmefwgraNzp+a5IrR8RcQG1mYDuS+2HK/rybo22XcCxhob8OiDEn8+ytkKyQ\nIpmrf9D+/68/ih6az0w1aakASMmFe8z/p6VgVQkCySCWWFG525BRdGmSImqVZ4xa\naQFN3L+oN+JJcCFTthLOAYo32JH+xLMz7PokzSL84g3b68h59hXDoMSwB10GthL5\nT8tqV6i5miKWwvfZ\n-----END CERTIFICATE-----", - "tls.key": "-----BEGIN RSA PRIVATE KEY-----\nMIIJKQIBAAKCAgEA1/+83/YNiEVKYvcuVwYGve6afsg1BYCn1+E9Uwgh0uwAenT/\nDKB8NhqoVxc7cZ2HaTI146IGmFICmctlTWvLPLglHmTobyOUV6tIJAjvzyEOpC45\n8hLGgbv8mhGXJWPxBVu7Wy6Hapz2bk0cEscfL7PHKaRu3D6r8/zbhhWAqe4EIt+N\nVYT6baaYBs7bPZQXs/sluKI+DNYuDeaAmoSuCc4ein6z0xDqCSMmPebzjns03ttB\n29vWL3eYY9dvgoCd+CPhXT/C4CHtvKbH+hOQYDtVF6MO1mmABAQTQWMR/00+QI0x\ntvuXtEPurla5dA0TN6ddCTOOcILKx62z5oc3Kqr+nHHa71zNzARUVaZ2vy1pRVr0\nDZgB7KqcFXhy/oy8IpmxUR1ASBDZl6B6RKrdQwvgLgmn3M/roNLAU+3nz4itpt/z\nf+X0suwdthrflic1R68z1SlYbyoGARWkZ/pOl6kLNVK2OsqQuICaajnW7t1oDd7z\n1+3hm+uoryDwvG6f3T9ZvWjKXYcKg7b+BjbFdahbDywDPgnhSz9AaoVWhR+GHIPr\njRClMpEkra/yGJFvH3UpXhgg9d0DrLZE51Z75a9SvnAjvdLuNhx4bJbwLBgNGsJM\nkupzBrw4iCfbKFcBbP8o0Xjtarj7T/mkWuQ1GjWqfyrD55NecBPNw5C9BR0CAwEA\nAQKCAgEAymuOrG/hJKiS2oX8tm8eWFZIELI9BigYozYhCzQexpSGqjwEXOf1H5sB\n0YQjIAlZwhrc57OK7KpGZ6x2BgUT1JZZqs80CBtWxIXuuF5rpje7id8MTLCNuTzb\nr+L2O4Mad0QNI5lKLH5mbt3yhiJ3NnQLHBpODjbpXGDFtTVne1hkJe5MfC1/psyt\nwguO6HllcTTWl93ruonpZPtz39qhYuz4MCAnE5DRUrjO+Mn7y7XoyUS+xnSRl7BD\nbqWRicJQyB+P7px3WyZQri+6TsCQ164iw2D64bLC1oCfLvLSBeh0g3gOdAX5mGTl\nRBpf98LdFJXSmXHodcYMlO5THqHu7mOE8zvPDbOzpwKftE11PS+lhuq/fREJnrAx\npbvTkv2c1nu90gkracv6PhRC8YhBIa2gqhoxY7rH7UpYa1c5QaJzg5ibiteTLRKC\ne9ZmfoPWaY2ksY4gBWZ/p2wokJ8U6ZHEsEfQS9WibMpqRsdINWQ9JnIBLKnTuqB0\nB29E9jHAl8rwMT2/DiIiVjHcdwpP37MxotKvYDFw+yDcZDeKTIh133XZNWyO/TcH\naDrNB0dymqunuNmfPts566AYErym0ndcmmLuGIKKE+l1h1+5CWjdsTdrkkXZK/w1\ni/krfLruQqQcW3Bpng8JAKirvGfYJxIEaCLqtepb7YaHhaI3gz0CggEBAPO0UQ6e\noPzMYmEegp2LjAfHZhwGV0fpiC6nxEWKoEE7Tb5zyB8rlkFIpQlXmljQvf3xDmq/\nTa3JlkaY290oFc0ypp9zUY/sUGyc3pvltxl0gLKOPnIkoP3ma2HzBxQRrGRdcFhH\nAHom80Bm9APm29L0MFuOuhGGxkGvQCxH+KmmohvZMUEqNIuWi8XB7maDXcAmSJ7x\nYdQAgLspRJ+kkZM+59XijyvYvg04xCu1FSop+Lol+xBwWAR5OaKnbZ9L+jKtzbxC\nIS7ERTlhsham2dYIm7SFcD/OcLV6luqreR0svS6HQis1kGxnNxkBAbrB1QZ+wLKp\nQztnOk70H/eWP5sCggEBAOLllCHuRloqEyzDT5sVbflCMTVsXmHGJ4/qI4An+etI\n3DComNLPAIBKYAiNgqWAm/wfLy5rHu2ZGzcPn7cQF/xKp00uDGKncQz3Z9JDofI1\nrpLH+t3LJ9l/EzQv1tpzwOU5rhFNmqrJnwy17BtOmlCKAQnVmyDkLyR9AhWkCTi8\nBLDq6mx1X61K6P11GAxAd70NFNzD8868Ddq2XInwEwXzf/FHQW/JVYZEAa7dn4KF\nwQ/tPSspP0vGzDfgNI64PtNePnZ/e00XXqA7la2OScro+SDSyXGlDKX4XhwwTDD1\n+u3VbUmjInpEJL3bU8c/qe36UhoseF1G0cm22sHqhacCggEAY3A+5r05KQ1oUwJ0\n/z2ybHYjJuo7cN9MLuVLg6iVzSgah8yMapOJYqf2l0JEe1rpOxXB8TKPyoqHo9S5\nWZsCklDJhiQysowVIMw9VNU9ichsvu6lckOZ4R/Ezxmv2LOBaQ5rScnm2vDLroqT\npIftSD1VAfbR21bnzGNqxuazAt44JS7RFyrWd+J8s7t2wCN3/HBij2Akr7Fo1XV4\nR7+JmtA/HpmsG5L7sT9pZAAmW6b2k1XuBH4im+iu6LxyUV5Z/5XFbbx597AkIs7H\nMNDx75BhoB4WeCKPAK29qJFBAPOBWdvc1u6rOGBBLhWoFAEFH/pWPFAuW626L/8S\nkB6hYwKCAQB3/JIec2Pu0Gs9c7eIOofilXdyWfF7YQ+Q0m+dmQZXvzr53F6ctGz+\natZoD3V0UhOq+063DFzZpuq2bmO2qiMU/uGENgLEtOlawwa7MZrVfD/qTSjD22gi\nY0njghzrfuUWEy+S5OgSwvaCAT5vnlyKlMBB1BzqAuFPOXA9w3ZA82TDribz3goP\nmRqm1iI2cG0ho2ZR7KnkvJvS+jbrlvJoZkFVdaoMFHtOum3tbDOrEVJsOrfrOC/J\nwcJDFiSVCKfonOEJRxcMSHx43amkkydAz3zXN8DhgTe0GSijXYMdLSdaWFAn7cYQ\nxDJt2CtwpaEWQRbj0nqAUTAlrLX4cC3nAoIBAQCl1cV86bYw8CKrCuf9TF0Kk5pd\nREdilDpks4Z1RH4MpBDWLtvMeQqlNsN+/RugKQExO0HTdZIyn7cBRRloD2xcNcJA\nG/rUMel/x4fhaEOE7Uw9rmTefvpcgWmtXw64sMA8KFA4oCXIcgbwL5Q+szqNNWAN\nabpgl0DnU06YyBDoK/7D0B8Kt3qS1N6XX+Z5wtPvglbD2HCYy6rdkqi8IbQ/6OeS\nwG7p/7g3JlOEyotMq9Cl2T0wTNDSLlma+mwc9mILITDXznWiLQSznE69mebWBUr3\nSbt91efH30inRx85H0pNJrpZsH0A6ayL0gTJSuUc0eJXYR5Po1gRQMOSIEWh\n-----END RSA PRIVATE KEY-----" - }, - "type": "kubernetes.io/tls" -}{ - "apiVersion": "configuration.konghq.com/v1", - "consumerGroups": [ - "example-consumer-group" - ], - "credentials": [ - "key-auth-example-user", - "jwt-auth-example-user", - "basic-auth-example-user", - "acl-group-example-user", - "mtls-auth-example-user" - ], - "custom_id": "1234567890", - "kind": "KongConsumer", - "metadata": { - "annotations": { - "konghq.com/plugins": "example-user-rate-limiting-advanced", - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-user" - }, - "username": "example-user" -}{ - "apiVersion": "configuration.konghq.com/v1beta1", - "kind": "KongConsumerGroup", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-consumer-group" - } -} \ No newline at end of file diff --git a/kong2kic/testdata/kicv2_gateway/output-expected.yaml b/kong2kic/testdata/kicv2_gateway/output-expected.yaml deleted file mode 100644 index 484b07206..000000000 --- a/kong2kic/testdata/kicv2_gateway/output-expected.yaml +++ /dev/null @@ -1,1181 +0,0 @@ -apiVersion: configuration.konghq.com/v1 -kind: KongIngress -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service-upstream -upstream: - algorithm: round-robin - hash_fallback: none - hash_on: none - hash_on_cookie_path: / - healthchecks: - active: - concurrency: 10 - headers: - x-another-header: - - bla - x-my-header: - - foo - - bar - healthy: - http_statuses: - - 200 - - 302 - interval: 0 - successes: 0 - http_path: / - https_sni: example.com - https_verify_certificate: true - timeout: 1 - type: http - unhealthy: - http_failures: 0 - http_statuses: - - 429 - - 404 - - 500 - - 501 - - 502 - - 503 - - 504 - - 505 - interval: 0 - tcp_failures: 0 - timeouts: 0 - passive: - healthy: - http_statuses: - - 200 - - 201 - - 202 - - 203 - - 204 - - 205 - - 206 - - 207 - - 208 - - 226 - - 300 - - 301 - - 302 - - 303 - - 304 - - 305 - - 306 - - 307 - - 308 - successes: 0 - type: http - unhealthy: - http_failures: 0 - http_statuses: - - 429 - - 500 - - 503 - tcp_failures: 0 - timeouts: 0 - threshold: 0 - host_header: example.com - slots: 10000 ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_client_headers: false - identifier: consumer - limit: - - 5 - namespace: example_namespace - strategy: local - sync_rate: -1 - window_size: - - 30 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service-rate-limiting-advanced -plugin: rate-limiting-advanced ---- -apiVersion: configuration.konghq.com/v1 -config: - aws_key: my_key - aws_region: us-west-2 - aws_secret: my_secret - function_name: my_function -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long9344b5559f -plugin: aws-lambda ---- -apiVersion: configuration.konghq.com/v1 -config: - credentials: true - exposed_headers: - - X-My-Header - headers: - - Authorization - max_age: 3600 - methods: - - GET - - POST - origins: - - example.com -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longfdeaa51f90 -plugin: cors ---- -apiVersion: configuration.konghq.com/v1 -config: - path: /var/log/kong/kong.log - reopen: true -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long3b4b1fae8e -plugin: file-log ---- -apiVersion: configuration.konghq.com/v1 -config: - content_type: application/json - http_endpoint: http://example.com/logs - keepalive: 60000 - method: POST - queue_size: 1000 - retry_count: 10 - timeout: 10000 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long59030a424c -plugin: http-log ---- -apiVersion: configuration.konghq.com/v1 -config: - allow: - - 192.168.0.1/24 - deny: - - 192.168.0.2/32 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longb44edd01cf -plugin: ip-restriction ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_client_headers: false - identifier: consumer - limit: - - 5 - namespace: example_namespace - strategy: local - sync_rate: -1 - window_size: - - 30 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longef35b834c6 -plugin: rate-limiting-advanced ---- -apiVersion: configuration.konghq.com/v1 -config: - message: Forbidden - status_code: 403 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longb2c08ebc54 -plugin: request-termination ---- -apiVersion: configuration.konghq.com/v1 -config: - limits: - limit_name: - minute: 10 - policy: local -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longc400f1ab11 -plugin: response-ratelimiting ---- -apiVersion: configuration.konghq.com/v1 -config: - host: example.com - port: 1234 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long47f9f5054d -plugin: tcp-log ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_credentials: false -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long26f9714514 -plugin: basic-auth ---- -apiVersion: configuration.konghq.com/v1 -config: - anonymous: null - claims_to_verify: - - exp - - nbf - header_names: - - Authorization - key_claim_name: kid - maximum_expiration: 3600 - run_on_preflight: true - secret_is_base64: false - uri_param_names: - - token -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long0239c8f63e -plugin: jwt ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_credentials: false - key_in_body: false - key_names: - - apikey - run_on_preflight: true -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long5494737f3e -plugin: key-auth ---- -apiVersion: configuration.konghq.com/v1 -config: - ca_certificates: - - cce8c384-721f-4f58-85dd-50834e3e733a - revocation_check_mode: SKIP - skip_consumer_lookup: false -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long89ae2d2b5d -plugin: mtls-auth ---- -apiVersion: configuration.konghq.com/v1 -config: - allow: - - admin -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longb2440ac898 -plugin: acl ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_client_headers: false - identifier: consumer - limit: - - 5 - namespace: example_namespace - strategy: local - sync_rate: -1 - window_size: - - 30 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-user-rate-limiting-advanced -plugin: rate-limiting-advanced ---- -apiVersion: gateway.networking.k8s.io/v1beta1 -kind: HTTPRoute -metadata: - annotations: - konghq.com/https-redirect-status-code: "302" - konghq.com/preserve-host: "true" - konghq.com/regex-priority: "1" - konghq.com/snis: example.com - konghq.com/strip-path: "false" - name: example-service--route-thisisaveryvery-long2093a020ca -spec: - hostnames: - - example.com - - another-example.com - - yet-another-example.com - parentRefs: - - name: kong - rules: - - backendRefs: - - name: example-service - port: 80 - filters: - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long9344b5559f - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longfdeaa51f90 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long3b4b1fae8e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long59030a424c - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb44edd01cf - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longef35b834c6 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2c08ebc54 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longc400f1ab11 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long47f9f5054d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long26f9714514 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long0239c8f63e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long5494737f3e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long89ae2d2b5d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2440ac898 - type: ExtensionRef - matches: - - headers: - - name: x-another-header - type: Exact - value: first-header-value,second-header-value - - name: x-my-header - type: RegularExpression - value: foos?bar$ - method: GET - path: - type: RegularExpression - value: /v1/example/?$ - - backendRefs: - - name: example-service - port: 80 - filters: - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long9344b5559f - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longfdeaa51f90 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long3b4b1fae8e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long59030a424c - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb44edd01cf - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longef35b834c6 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2c08ebc54 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longc400f1ab11 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long47f9f5054d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long26f9714514 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long0239c8f63e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long5494737f3e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long89ae2d2b5d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2440ac898 - type: ExtensionRef - matches: - - headers: - - name: x-another-header - type: Exact - value: first-header-value,second-header-value - - name: x-my-header - type: RegularExpression - value: foos?bar$ - method: POST - path: - type: RegularExpression - value: /v1/example/?$ - - backendRefs: - - name: example-service - port: 80 - filters: - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long9344b5559f - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longfdeaa51f90 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long3b4b1fae8e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long59030a424c - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb44edd01cf - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longef35b834c6 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2c08ebc54 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longc400f1ab11 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long47f9f5054d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long26f9714514 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long0239c8f63e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long5494737f3e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long89ae2d2b5d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2440ac898 - type: ExtensionRef - matches: - - headers: - - name: x-another-header - type: Exact - value: first-header-value,second-header-value - - name: x-my-header - type: RegularExpression - value: foos?bar$ - method: GET - path: - type: PathPrefix - value: /v1/another-example - - backendRefs: - - name: example-service - port: 80 - filters: - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long9344b5559f - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longfdeaa51f90 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long3b4b1fae8e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long59030a424c - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb44edd01cf - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longef35b834c6 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2c08ebc54 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longc400f1ab11 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long47f9f5054d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long26f9714514 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long0239c8f63e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long5494737f3e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long89ae2d2b5d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2440ac898 - type: ExtensionRef - matches: - - headers: - - name: x-another-header - type: Exact - value: first-header-value,second-header-value - - name: x-my-header - type: RegularExpression - value: foos?bar$ - method: POST - path: - type: PathPrefix - value: /v1/another-example - - backendRefs: - - name: example-service - port: 80 - filters: - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long9344b5559f - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longfdeaa51f90 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long3b4b1fae8e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long59030a424c - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb44edd01cf - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longef35b834c6 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2c08ebc54 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longc400f1ab11 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long47f9f5054d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long26f9714514 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long0239c8f63e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long5494737f3e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long89ae2d2b5d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2440ac898 - type: ExtensionRef - matches: - - headers: - - name: x-another-header - type: Exact - value: first-header-value,second-header-value - - name: x-my-header - type: RegularExpression - value: foos?bar$ - method: GET - path: - type: PathPrefix - value: /v1/yet-another-example - - backendRefs: - - name: example-service - port: 80 - filters: - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long9344b5559f - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longfdeaa51f90 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long3b4b1fae8e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long59030a424c - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb44edd01cf - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longef35b834c6 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2c08ebc54 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longc400f1ab11 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long47f9f5054d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long26f9714514 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long0239c8f63e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long5494737f3e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long89ae2d2b5d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2440ac898 - type: ExtensionRef - matches: - - headers: - - name: x-another-header - type: Exact - value: first-header-value,second-header-value - - name: x-my-header - type: RegularExpression - value: foos?bar$ - method: POST - path: - type: PathPrefix - value: /v1/yet-another-example ---- -apiVersion: v1 -kind: Service -metadata: - annotations: - konghq.com/connect-timeout: "5000" - konghq.com/override: example-service-upstream - konghq.com/path: /v1 - konghq.com/plugins: example-service-rate-limiting-advanced - konghq.com/protocol: http - konghq.com/read-timeout: "60000" - konghq.com/retries: "5" - konghq.com/write-timeout: "60000" - name: example-service -spec: - ports: - - port: 80 - protocol: TCP - targetPort: 80 - selector: - app: example-service ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: key-auth-example-user -stringData: - key: my_api_key - kongCredType: key-auth ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: jwt-auth-example-user -stringData: - algorithm: HS256 - key: my_jwt_secret - kongCredType: jwt - rsa_public_key: |- - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxXzYS5yESbekTF3xLiQX - ZZZfXt0S/nzFp3f2Oux3W7/ydvZ8XSd8+s+wm5oqEcSV9n+5n3ENZbt1A/wgnGI3 - oWrv0yRB9HugzTIGPpI1AQv9Z4p8E44RrB74/uTxYwb9+4yvpuz/fzTt3Gz+Kzc4 - 4fGGq8VpGMFj6AE65ZcOAHHUJe4VuoreBXLYDJcHl2WPIdNKDGscFjElDneLRhWQ - DfxekDJIQMWCjyBEXacfP6cc9U8Qld6TuVcwi1P2xb8tBDD4MIFL/psfzUhfv1Lw - O/XZEffJxCqkQn7dsCYy3wpaTjb6XmJ5j0Dbml4f0Bv40Y1mjlAf7C662Mbuguf6 - ewIDAQAB - -----END PUBLIC KEY----- - secret: my_secret_key ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: basic-auth-example-user -stringData: - kongCredType: basic-auth - password: my_basic_password - username: my_basic_user ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: acl-group-example-user -stringData: - group: acl_group - kongCredType: acl ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: mtls-auth-example-user -stringData: - id: cce8c384-721f-4f58-85dd-50834e3e733a - kongCredType: mtls-auth - subject_name: example-user@example.com -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: ca-cert-a672ab52d2341203bd70116b456413d7ac3ffc162abbf -stringData: - ca.crt: | - -----BEGIN CERTIFICATE----- - MIIBfDCCASKgAwIBAgIRAJqcZC1VSvSQLMN1+7yAeswwCgYIKoZIzj0EAwIwHDEa - MBgGA1UEAxMRRGVtbyBLb25nIFJvb3QgQ0EwHhcNMjIwNjEzMTMzNzMzWhcNMjcw - NjEzMTkzNzMzWjAcMRowGAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTBZMBMGByqG - SM49AgEGCCqGSM49AwEHA0IABOGR89IyhreSHRAi6wp9a5DBIDp4YYSdWzuEdlNx - 7pX1G4T7x68xUXJZXRUPFyT8Xzn5KwCJm8RVT+nAhrsUx6SjRTBDMA4GA1UdDwEB - /wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBQ9CUiOPhjp7KD2 - ScRDxX4IzDOrNzAKBggqhkjOPQQDAgNIADBFAiEAw6Dov0c0L++1W9VufAfSMdNR - PSDfPU0MiUiG59/VIBICIEFn/6c5eQc3hUUBL74/RmNT2b1zxBmp7RiPXJAnAAwJ - -----END CERTIFICATE----- - ca.digest: f1baffe9fe9cf8497e38a4271d67fab44423678b7e7c0f677a50f37c113d81b5 -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: ca-cert-a4f087c2ee00e6d43cfb4f6884fc1e79f7e6e08e84471 -stringData: - ca.crt: | - -----BEGIN CERTIFICATE----- - MIIBqTCCAVCgAwIBAgIQb5LqGa9gS3+Mc2ntWfSoJjAKBggqhkjOPQQDAjAcMRow - GAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTAeFw0yMjA2MTMxMzM5MTVaFw0yMzA2 - MTMxOTM5MTVaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBSb290IEludGVybWVkaWF0 - ZTEgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQImvnSuvXkGy88lvx8a7of - e0MEMRI2siVvybvWXNpeXXlixgaq7weJ7pewf3HywfO68Va6kn8ehWh7s0D7SLHM - o2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4E - FgQUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwHwYDVR0jBBgwFoAUPQlIjj4Y6eyg9knE - Q8V+CMwzqzcwCgYIKoZIzj0EAwIDRwAwRAIgNZ+JPA1OqF5DsPapAZ2YsUOgIpn3 - ZbQuYKCAV0SD4EcCIFnfA5rWrc1AgtUw5inJQqJQRNgoPuC14vACqI48BiRl - -----END CERTIFICATE----- - ca.digest: dbef7ed285fb292e24f84ffba93c48d92fa322387d85469c460c655abedd5308 -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: ca-cert-6b095c7ff377b01252a4dfec59c582fe32934fa7ed0cf -stringData: - ca.crt: | - -----BEGIN CERTIFICATE----- - MIIBujCCAV+gAwIBAgIRAMkGpj7WZf+2RFE/q7ZhejEwCgYIKoZIzj0EAwIwKjEo - MCYGA1UEAxMfRGVtbyBLb25nIFJvb3QgSW50ZXJtZWRpYXRlMSBDQTAeFw0yMjA2 - MTMxMzQwNTFaFw0yMjEyMTMwNDQwNTFaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBS - b290IEludGVybWVkaWF0ZTIgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQB - my/zhZ3F2HvHFqtQzuD3lXX8SeYakxiBQvaGkGSLKD67N3vh7iC2rTSdj/vAs8ws - Y9X+mXzS6GDKC8PbSX6xo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgw - BgEB/wIBADAdBgNVHQ4EFgQURwCm53YPStZoAMfnVyknH4IgZa4wHwYDVR0jBBgw - FoAUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwCgYIKoZIzj0EAwIDSQAwRgIhAN1pkUKc - azM4PiXOnkILB2KBDIF4XpHf+4ThDMODzXP8AiEA45KXA3qMrRPQV1oBfWZ3hLgX - gxUhveuHBXMWnzUbn6U= - -----END CERTIFICATE----- - ca.digest: 45b2b6dd9d4102955b1b1e4b540e677f140521462ed4f22fa5a713863ca84600 -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: cert-0ee0e1584c8637facac95bd5fce315367dee124c0086d41e -stringData: - tls.crt: |- - -----BEGIN CERTIFICATE----- - MIIECTCCAvGgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyAwDQYJKoZIhvcNAQEL - BQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM - CUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY - MBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u - Z2hxLmNvbTAeFw0yMTAxMTUxMTE5NDNaFw0yMjA1MzAxMTE5NDNaMIGRMQswCQYD - VQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx - EDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFzAVBgNVBAMMDnBy - b3h5LmtvbmcubGFuMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29uZ2hxLmNvbTCCASIw - DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJUbKiqoCK1BTNk/7l42n6ukyTEu - eLyB23e/90PzT/oz8wZzgwTodzbFAS2VtFr1EKqFzor0DrXp9CLnebOdiAR3I6LD - /WY/x0KW3lx3F35fGiUOSLPTH8zeiDTMx11CcKDxesA+M2/s5q0igkOQ4z4w3voz - m5a52IcQTSA8K5knNU1qUZBLpc+khxFcaheEK1jsISJJhcdizZBfGdk8S1vpyj5F - uCZ7oaRvNA6imHjSJwpgo36zd84TgrIgVj9R4QtJysWy/X+bbaKUiKBWwAtd4+DT - EP90l/ny9szu2fijk4/6k1ntXufGTyvM+J0/qJ13e99TVYOVanITnpTO+6cCAwEA - AaNWMFQwHwYDVR0jBBgwFoAUdskpf0wJRQxjtzQFZciWmUfl2bcwCQYDVR0TBAIw - ADALBgNVHQ8EBAMCBPAwGQYDVR0RBBIwEIIOcHJveHkua29uZy5sYW4wDQYJKoZI - hvcNAQELBQADggEBAJVrTWQRQzNtypa9OXFYADm8Fay1VMop3BY2kh0tfYgQEJ/4 - pJUj6CaszQZ/Aix6LaPnXFcoPCDqqv00mgju86PMamr/zA9USXk8eTmzJkp5RklS - GdqiXboqESiQVvaNz3kdW7wgNz4FwaGCzkEi/dcc2LdtzLpWizx+TlxMMqjonUUM - ovZgZo+OlhWRsDVT/qy5SFtA0vlVNtdBr2egXb1H7J8UDC+fax/iKa7+fBUHZOO9 - Fk9U8bxgfQ+jPIVVL8CfAtR68Sos7NpWH0S2emqZRnQvf0MSNdkTQKWn4qR9sckj - Ewxs5FbrMmgCOgwk1PtgRmdP3RME0HwK/B03saQ= - -----END CERTIFICATE----- - tls.key: |- - -----BEGIN PRIVATE KEY----- - MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCVGyoqqAitQUzZ - P+5eNp+rpMkxLni8gdt3v/dD80/6M/MGc4ME6Hc2xQEtlbRa9RCqhc6K9A616fQi - 53mznYgEdyOiw/1mP8dClt5cdxd+XxolDkiz0x/M3og0zMddQnCg8XrAPjNv7Oat - IoJDkOM+MN76M5uWudiHEE0gPCuZJzVNalGQS6XPpIcRXGoXhCtY7CEiSYXHYs2Q - XxnZPEtb6co+Rbgme6GkbzQOoph40icKYKN+s3fOE4KyIFY/UeELScrFsv1/m22i - lIigVsALXePg0xD/dJf58vbM7tn4o5OP+pNZ7V7nxk8rzPidP6idd3vfU1WDlWpy - E56UzvunAgMBAAECggEAcq7lHNAHdHLgT8yrY41x/AwPryNGO/9JNW7SGVKAdjoU - tyaLZHAEmXynLk+R28/YFMA8H4Yd9m9OlrYhVjRZFM4p+5vxP/7YHPB7cPUsfcda - DZxR8PX25JVYf/vtb16V0ERLnKd62qCEwC/lr2A2WHQwXJLrHeAtmZzBJYUCJ5Xj - Dv1ZhyFjknswaV0vGXe6njTI6CzMQDTGysoagpCCo7RWgzjLREg2BGWd2UQpY4AW - nYAP4QNt82UMQbgIqsEMj64mzS9Q+o1P84J1naSP5sCI22LeFRp6iezZc+D8EH/5 - RNONGSNWl3g6bsvN1VywYwjWn+waD3XAjXUu+peUgQKBgQDDu1QP28oSMKivHdfo - kQ1HrTNBRc9eWeAMZFuIbbPLN8rdEibpOm3DwTqithnahqS0NLOsBnXNtuLw1Qr/ - zmOzn0yDO5XG8dlKr9vqWeBLdcRydLJBZwqEzWf4JwwwgfK3rItRaIbnAxnGUTS5 - SrrhNfBAIGS9jx5X2kvLC7hFQQKBgQDDBIrpLTIjRDloWZcu03z9Bhb8jQCyGb5C - 4MYs+duCnQIdNq/+maPspJzbVmF4b6S1zIPweI3fMvMeqRTbuf+drpElst1buFTO - P0UMMn4V+4qGIOOkIy5JIKwR8sJD9tNDUPtxuDEotTB9IyWx6pdmCFz5v/bggDCu - reoqflL+5wKBgQCDvb+L2QS+j4/KJk0flRoaJ2K7SVCVEesyjA3r2uLMImZhvAkC - rDgbLSDZSbZHFp8fR+WzILoD11gSf2Ki4PjMeqkWH3HlcP0vPwTHTO0h/UdXPmKI - kOFMl7CmHyoeMCj9JZ60EaXTMYwUpq3VFY6JbTOjBeqoh/8FZMHlDaNewQKBgCHg - ECEg8KyflTlDFrfTlMp+3E9STuShBCOp18LIRBEUJOHeNgQLvCXHElgnURcSjZHm - zKRgzIQQ3Zpd1Hm2fWhuglgCEeF0y4ZoBx5vRueaoh1aaTCBy/B39GvJt2UG4vu2 - fXbrf96KWrnh+RJGpbXbjgr0BXZJzisJmrt25gPRAoGBAI3c+INpQXwrE+LBzCPu - LwIVvkm5NpeIlKQtDNrqG1QvUhqyZ2/Xitc4FyiccW7WHxkGKGZyj7GbmpqEOnyY - iVku0LSftZgycet2uMdp0HaVAgi5S6aVf5yN0U/8R5ToxcbuEfqwrBIyRgse8lx3 - NNSvLxPAempmiFPSk9AtobYV - -----END PRIVATE KEY----- -type: kubernetes.io/tls ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: cert-b12464ec431576239dd9cc2545d528f6cbdbd988cf076323 -stringData: - tls.crt: |- - -----BEGIN CERTIFICATE----- - MIIFeDCCBGCgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyQwDQYJKoZIhvcNAQEL - BQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM - CUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY - MBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u - Z2hxLmNvbTAeFw0yMTAxMjAxNTA0NDVaFw0yMjAxMjAxNTA0NDVaMIGQMQswCQYD - VQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx - EDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFjAUBgNVBAMMDW10 - bHMtY29uc3VtZXIxHTAbBgkqhkiG9w0BCQEWDnN0dUBrb25naHEuY29tMIICIjAN - BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1/+83/YNiEVKYvcuVwYGve6afsg1 - BYCn1+E9Uwgh0uwAenT/DKB8NhqoVxc7cZ2HaTI146IGmFICmctlTWvLPLglHmTo - byOUV6tIJAjvzyEOpC458hLGgbv8mhGXJWPxBVu7Wy6Hapz2bk0cEscfL7PHKaRu - 3D6r8/zbhhWAqe4EIt+NVYT6baaYBs7bPZQXs/sluKI+DNYuDeaAmoSuCc4ein6z - 0xDqCSMmPebzjns03ttB29vWL3eYY9dvgoCd+CPhXT/C4CHtvKbH+hOQYDtVF6MO - 1mmABAQTQWMR/00+QI0xtvuXtEPurla5dA0TN6ddCTOOcILKx62z5oc3Kqr+nHHa - 71zNzARUVaZ2vy1pRVr0DZgB7KqcFXhy/oy8IpmxUR1ASBDZl6B6RKrdQwvgLgmn - 3M/roNLAU+3nz4itpt/zf+X0suwdthrflic1R68z1SlYbyoGARWkZ/pOl6kLNVK2 - OsqQuICaajnW7t1oDd7z1+3hm+uoryDwvG6f3T9ZvWjKXYcKg7b+BjbFdahbDywD - PgnhSz9AaoVWhR+GHIPrjRClMpEkra/yGJFvH3UpXhgg9d0DrLZE51Z75a9SvnAj - vdLuNhx4bJbwLBgNGsJMkupzBrw4iCfbKFcBbP8o0Xjtarj7T/mkWuQ1GjWqfyrD - 55NecBPNw5C9BR0CAwEAAaOBxTCBwjAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQE - AwIFoDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgQ2xpZW50IENl - cnRpZmljYXRlMB0GA1UdDgQWBBSV3F+eicU8SVT4LcDJ6eMzP0todzAfBgNVHSME - GDAWgBR2ySl/TAlFDGO3NAVlyJaZR+XZtzAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0l - BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4IBAQB5L0OZ - WELG9Pw6Ol1BsZYgpLR4PGNBB9dKm/9dd+q+ohZVFCfXcjZ3YOU1vh/HHQrALRNY - I58JxcVCOx/qIW2uA0iSCqIT0sNb9cJLxfZf7X+BzPPPnu0ugUJp7GzLNnHitrLC - Xb1nmmefwgraNzp+a5IrR8RcQG1mYDuS+2HK/rybo22XcCxhob8OiDEn8+ytkKyQ - Ipmrf9D+/68/ih6az0w1aakASMmFe8z/p6VgVQkCySCWWFG525BRdGmSImqVZ4xa - aQFN3L+oN+JJcCFTthLOAYo32JH+xLMz7PokzSL84g3b68h59hXDoMSwB10GthL5 - T8tqV6i5miKWwvfZ - -----END CERTIFICATE----- - tls.key: |- - -----BEGIN RSA PRIVATE KEY----- - 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 - -----END RSA PRIVATE KEY----- -type: kubernetes.io/tls ---- -apiVersion: configuration.konghq.com/v1 -consumerGroups: -- example-consumer-group -credentials: -- key-auth-example-user -- jwt-auth-example-user -- basic-auth-example-user -- acl-group-example-user -- mtls-auth-example-user -custom_id: "1234567890" -kind: KongConsumer -metadata: - annotations: - konghq.com/plugins: example-user-rate-limiting-advanced - kubernetes.io/ingress.class: kong - name: example-user -username: example-user ---- -apiVersion: configuration.konghq.com/v1beta1 -kind: KongConsumerGroup -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-consumer-group ---- diff --git a/kong2kic/testdata/kicv2_ingress/output-expected.json b/kong2kic/testdata/kicv2_ingress/output-expected.json deleted file mode 100644 index 37e4191ed..000000000 --- a/kong2kic/testdata/kicv2_ingress/output-expected.json +++ /dev/null @@ -1,750 +0,0 @@ -{ - "apiVersion": "configuration.konghq.com/v1", - "kind": "KongIngress", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service-upstream" - }, - "upstream": { - "algorithm": "round-robin", - "hash_fallback": "none", - "hash_on": "none", - "hash_on_cookie_path": "/", - "healthchecks": { - "active": { - "concurrency": 10, - "headers": { - "x-another-header": [ - "bla" - ], - "x-my-header": [ - "foo", - "bar" - ] - }, - "healthy": { - "http_statuses": [ - 200, - 302 - ], - "interval": 0, - "successes": 0 - }, - "http_path": "/", - "https_sni": "example.com", - "https_verify_certificate": true, - "timeout": 1, - "type": "http", - "unhealthy": { - "http_failures": 0, - "http_statuses": [ - 429, - 404, - 500, - 501, - 502, - 503, - 504, - 505 - ], - "interval": 0, - "tcp_failures": 0, - "timeouts": 0 - } - }, - "passive": { - "healthy": { - "http_statuses": [ - 200, - 201, - 202, - 203, - 204, - 205, - 206, - 207, - 208, - 226, - 300, - 301, - 302, - 303, - 304, - 305, - 306, - 307, - 308 - ], - "successes": 0 - }, - "type": "http", - "unhealthy": { - "http_failures": 0, - "http_statuses": [ - 429, - 500, - 503 - ], - "tcp_failures": 0, - "timeouts": 0 - } - }, - "threshold": 0 - }, - "host_header": "example.com", - "slots": 10000 - } -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_client_headers": false, - "identifier": "consumer", - "limit": [ - 5 - ], - "namespace": "example_namespace", - "strategy": "local", - "sync_rate": -1, - "window_size": [ - 30 - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service-rate-limiting-advanced" - }, - "plugin": "rate-limiting-advanced" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "aws_key": "my_key", - "aws_region": "us-west-2", - "aws_secret": "my_secret", - "function_name": "my_function" - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "plugin": "aws-lambda" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "credentials": true, - "exposed_headers": [ - "X-My-Header" - ], - "headers": [ - "Authorization" - ], - "max_age": 3600, - "methods": [ - "GET", - "POST" - ], - "origins": [ - "example.com" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "plugin": "cors" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "path": "/var/log/kong/kong.log", - "reopen": true - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "plugin": "file-log" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "content_type": "application/json", - "http_endpoint": "http://example.com/logs", - "keepalive": 60000, - "method": "POST", - "queue_size": 1000, - "retry_count": 10, - "timeout": 10000 - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "plugin": "http-log" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "allow": [ - "192.168.0.1/24" - ], - "deny": [ - "192.168.0.2/32" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "plugin": "ip-restriction" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_client_headers": false, - "identifier": "consumer", - "limit": [ - 5 - ], - "namespace": "example_namespace", - "strategy": "local", - "sync_rate": -1, - "window_size": [ - 30 - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "plugin": "rate-limiting-advanced" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "message": "Forbidden", - "status_code": 403 - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "plugin": "request-termination" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "limits": { - "limit_name": { - "minute": 10 - } - }, - "policy": "local" - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "plugin": "response-ratelimiting" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "host": "example.com", - "port": 1234 - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "plugin": "tcp-log" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_credentials": false - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "plugin": "basic-auth" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "anonymous": null, - "claims_to_verify": [ - "exp", - "nbf" - ], - "header_names": [ - "Authorization" - ], - "key_claim_name": "kid", - "maximum_expiration": 3600, - "run_on_preflight": true, - "secret_is_base64": false, - "uri_param_names": [ - "token" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "plugin": "jwt" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_credentials": false, - "key_in_body": false, - "key_names": [ - "apikey" - ], - "run_on_preflight": true - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "plugin": "key-auth" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "ca_certificates": [ - "cce8c384-721f-4f58-85dd-50834e3e733a" - ], - "revocation_check_mode": "SKIP", - "skip_consumer_lookup": false - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "plugin": "mtls-auth" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "allow": [ - "admin" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "plugin": "acl" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_client_headers": false, - "identifier": "consumer", - "limit": [ - 5 - ], - "namespace": "example_namespace", - "strategy": "local", - "sync_rate": -1, - "window_size": [ - 30 - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-user-rate-limiting-advanced" - }, - "plugin": "rate-limiting-advanced" -}{ - "apiVersion": "networking.k8s.io/v1", - "kind": "Ingress", - "metadata": { - "annotations": { - "konghq.com/headers.x-another-header": "first-header-value,second-header-value", - "konghq.com/headers.x-my-header": "~*foos?bar$", - "konghq.com/https-redirect-status-code": "302", - "konghq.com/methods": "GET,POST", - "konghq.com/plugins": "example-service--route-thisisaveryvery-long9344b5559f,example-service--route-thisisaveryvery-longfdeaa51f90,example-service--route-thisisaveryvery-long3b4b1fae8e,example-service--route-thisisaveryvery-long59030a424c,example-service--route-thisisaveryvery-longb44edd01cf,example-service--route-thisisaveryvery-longef35b834c6,example-service--route-thisisaveryvery-longb2c08ebc54,example-service--route-thisisaveryvery-longc400f1ab11,example-service--route-thisisaveryvery-long47f9f5054d,example-service--route-thisisaveryvery-long26f9714514,example-service--route-thisisaveryvery-long0239c8f63e,example-service--route-thisisaveryvery-long5494737f3e,example-service--route-thisisaveryvery-long89ae2d2b5d,example-service--route-thisisaveryvery-longb2440ac898", - "konghq.com/preserve-host": "true", - "konghq.com/protocols": "http,https", - "konghq.com/regex-priority": "1", - "konghq.com/snis": "example.com", - "konghq.com/strip-path": "false" - }, - "name": "example-service--route-thisisaveryvery-long2093a020ca" - }, - "spec": { - "ingressClassName": "kong", - "rules": [ - { - "host": "example.com", - "http": { - "paths": [ - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/~/v1/example/?$", - "pathType": "ImplementationSpecific" - }, - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/v1/another-example", - "pathType": "ImplementationSpecific" - }, - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/v1/yet-another-example", - "pathType": "ImplementationSpecific" - } - ] - } - }, - { - "host": "another-example.com", - "http": { - "paths": [ - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/~/v1/example/?$", - "pathType": "ImplementationSpecific" - }, - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/v1/another-example", - "pathType": "ImplementationSpecific" - }, - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/v1/yet-another-example", - "pathType": "ImplementationSpecific" - } - ] - } - }, - { - "host": "yet-another-example.com", - "http": { - "paths": [ - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/~/v1/example/?$", - "pathType": "ImplementationSpecific" - }, - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/v1/another-example", - "pathType": "ImplementationSpecific" - }, - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/v1/yet-another-example", - "pathType": "ImplementationSpecific" - } - ] - } - } - ] - } -}{ - "apiVersion": "v1", - "kind": "Service", - "metadata": { - "annotations": { - "konghq.com/connect-timeout": "5000", - "konghq.com/override": "example-service-upstream", - "konghq.com/path": "/v1", - "konghq.com/plugins": "example-service-rate-limiting-advanced", - "konghq.com/protocol": "http", - "konghq.com/read-timeout": "60000", - "konghq.com/retries": "5", - "konghq.com/write-timeout": "60000" - }, - "name": "example-service" - }, - "spec": { - "ports": [ - { - "port": 80, - "protocol": "TCP", - "targetPort": 80 - } - ], - "selector": { - "app": "example-service" - } - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "key-auth-example-user" - }, - "stringData": { - "key": "my_api_key", - "kongCredType": "key-auth" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "jwt-auth-example-user" - }, - "stringData": { - "algorithm": "HS256", - "key": "my_jwt_secret", - "kongCredType": "jwt", - "rsa_public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxXzYS5yESbekTF3xLiQX\nZZZfXt0S/nzFp3f2Oux3W7/ydvZ8XSd8+s+wm5oqEcSV9n+5n3ENZbt1A/wgnGI3\noWrv0yRB9HugzTIGPpI1AQv9Z4p8E44RrB74/uTxYwb9+4yvpuz/fzTt3Gz+Kzc4\n4fGGq8VpGMFj6AE65ZcOAHHUJe4VuoreBXLYDJcHl2WPIdNKDGscFjElDneLRhWQ\nDfxekDJIQMWCjyBEXacfP6cc9U8Qld6TuVcwi1P2xb8tBDD4MIFL/psfzUhfv1Lw\nO/XZEffJxCqkQn7dsCYy3wpaTjb6XmJ5j0Dbml4f0Bv40Y1mjlAf7C662Mbuguf6\newIDAQAB\n-----END PUBLIC KEY-----", - "secret": "my_secret_key" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "basic-auth-example-user" - }, - "stringData": { - "kongCredType": "basic-auth", - "password": "my_basic_password", - "username": "my_basic_user" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "acl-group-example-user" - }, - "stringData": { - "group": "acl_group", - "kongCredType": "acl" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "mtls-auth-example-user" - }, - "stringData": { - "id": "cce8c384-721f-4f58-85dd-50834e3e733a", - "kongCredType": "mtls-auth", - "subject_name": "example-user@example.com" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "ca-cert-a672ab52d2341203bd70116b456413d7ac3ffc162abbf" - }, - "stringData": { - "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIBfDCCASKgAwIBAgIRAJqcZC1VSvSQLMN1+7yAeswwCgYIKoZIzj0EAwIwHDEa\nMBgGA1UEAxMRRGVtbyBLb25nIFJvb3QgQ0EwHhcNMjIwNjEzMTMzNzMzWhcNMjcw\nNjEzMTkzNzMzWjAcMRowGAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTBZMBMGByqG\nSM49AgEGCCqGSM49AwEHA0IABOGR89IyhreSHRAi6wp9a5DBIDp4YYSdWzuEdlNx\n7pX1G4T7x68xUXJZXRUPFyT8Xzn5KwCJm8RVT+nAhrsUx6SjRTBDMA4GA1UdDwEB\n/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBQ9CUiOPhjp7KD2\nScRDxX4IzDOrNzAKBggqhkjOPQQDAgNIADBFAiEAw6Dov0c0L++1W9VufAfSMdNR\nPSDfPU0MiUiG59/VIBICIEFn/6c5eQc3hUUBL74/RmNT2b1zxBmp7RiPXJAnAAwJ\n-----END CERTIFICATE-----\n", - "ca.digest": "f1baffe9fe9cf8497e38a4271d67fab44423678b7e7c0f677a50f37c113d81b5" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "ca-cert-a4f087c2ee00e6d43cfb4f6884fc1e79f7e6e08e84471" - }, - "stringData": { - "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIBqTCCAVCgAwIBAgIQb5LqGa9gS3+Mc2ntWfSoJjAKBggqhkjOPQQDAjAcMRow\nGAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTAeFw0yMjA2MTMxMzM5MTVaFw0yMzA2\nMTMxOTM5MTVaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBSb290IEludGVybWVkaWF0\nZTEgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQImvnSuvXkGy88lvx8a7of\ne0MEMRI2siVvybvWXNpeXXlixgaq7weJ7pewf3HywfO68Va6kn8ehWh7s0D7SLHM\no2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4E\nFgQUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwHwYDVR0jBBgwFoAUPQlIjj4Y6eyg9knE\nQ8V+CMwzqzcwCgYIKoZIzj0EAwIDRwAwRAIgNZ+JPA1OqF5DsPapAZ2YsUOgIpn3\nZbQuYKCAV0SD4EcCIFnfA5rWrc1AgtUw5inJQqJQRNgoPuC14vACqI48BiRl\n-----END CERTIFICATE-----\n", - "ca.digest": "dbef7ed285fb292e24f84ffba93c48d92fa322387d85469c460c655abedd5308" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "ca-cert-6b095c7ff377b01252a4dfec59c582fe32934fa7ed0cf" - }, - "stringData": { - "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIBujCCAV+gAwIBAgIRAMkGpj7WZf+2RFE/q7ZhejEwCgYIKoZIzj0EAwIwKjEo\nMCYGA1UEAxMfRGVtbyBLb25nIFJvb3QgSW50ZXJtZWRpYXRlMSBDQTAeFw0yMjA2\nMTMxMzQwNTFaFw0yMjEyMTMwNDQwNTFaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBS\nb290IEludGVybWVkaWF0ZTIgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQB\nmy/zhZ3F2HvHFqtQzuD3lXX8SeYakxiBQvaGkGSLKD67N3vh7iC2rTSdj/vAs8ws\nY9X+mXzS6GDKC8PbSX6xo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgw\nBgEB/wIBADAdBgNVHQ4EFgQURwCm53YPStZoAMfnVyknH4IgZa4wHwYDVR0jBBgw\nFoAUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwCgYIKoZIzj0EAwIDSQAwRgIhAN1pkUKc\nazM4PiXOnkILB2KBDIF4XpHf+4ThDMODzXP8AiEA45KXA3qMrRPQV1oBfWZ3hLgX\ngxUhveuHBXMWnzUbn6U=\n-----END CERTIFICATE-----\n", - "ca.digest": "45b2b6dd9d4102955b1b1e4b540e677f140521462ed4f22fa5a713863ca84600" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "cert-0ee0e1584c8637facac95bd5fce315367dee124c0086d41e" - }, - "stringData": { - "tls.crt": "-----BEGIN CERTIFICATE-----\nMIIECTCCAvGgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyAwDQYJKoZIhvcNAQEL\nBQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM\nCUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY\nMBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u\nZ2hxLmNvbTAeFw0yMTAxMTUxMTE5NDNaFw0yMjA1MzAxMTE5NDNaMIGRMQswCQYD\nVQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx\nEDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFzAVBgNVBAMMDnBy\nb3h5LmtvbmcubGFuMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29uZ2hxLmNvbTCCASIw\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJUbKiqoCK1BTNk/7l42n6ukyTEu\neLyB23e/90PzT/oz8wZzgwTodzbFAS2VtFr1EKqFzor0DrXp9CLnebOdiAR3I6LD\n/WY/x0KW3lx3F35fGiUOSLPTH8zeiDTMx11CcKDxesA+M2/s5q0igkOQ4z4w3voz\nm5a52IcQTSA8K5knNU1qUZBLpc+khxFcaheEK1jsISJJhcdizZBfGdk8S1vpyj5F\nuCZ7oaRvNA6imHjSJwpgo36zd84TgrIgVj9R4QtJysWy/X+bbaKUiKBWwAtd4+DT\nEP90l/ny9szu2fijk4/6k1ntXufGTyvM+J0/qJ13e99TVYOVanITnpTO+6cCAwEA\nAaNWMFQwHwYDVR0jBBgwFoAUdskpf0wJRQxjtzQFZciWmUfl2bcwCQYDVR0TBAIw\nADALBgNVHQ8EBAMCBPAwGQYDVR0RBBIwEIIOcHJveHkua29uZy5sYW4wDQYJKoZI\nhvcNAQELBQADggEBAJVrTWQRQzNtypa9OXFYADm8Fay1VMop3BY2kh0tfYgQEJ/4\npJUj6CaszQZ/Aix6LaPnXFcoPCDqqv00mgju86PMamr/zA9USXk8eTmzJkp5RklS\nGdqiXboqESiQVvaNz3kdW7wgNz4FwaGCzkEi/dcc2LdtzLpWizx+TlxMMqjonUUM\novZgZo+OlhWRsDVT/qy5SFtA0vlVNtdBr2egXb1H7J8UDC+fax/iKa7+fBUHZOO9\nFk9U8bxgfQ+jPIVVL8CfAtR68Sos7NpWH0S2emqZRnQvf0MSNdkTQKWn4qR9sckj\nEwxs5FbrMmgCOgwk1PtgRmdP3RME0HwK/B03saQ=\n-----END CERTIFICATE-----", - "tls.key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCVGyoqqAitQUzZ\nP+5eNp+rpMkxLni8gdt3v/dD80/6M/MGc4ME6Hc2xQEtlbRa9RCqhc6K9A616fQi\n53mznYgEdyOiw/1mP8dClt5cdxd+XxolDkiz0x/M3og0zMddQnCg8XrAPjNv7Oat\nIoJDkOM+MN76M5uWudiHEE0gPCuZJzVNalGQS6XPpIcRXGoXhCtY7CEiSYXHYs2Q\nXxnZPEtb6co+Rbgme6GkbzQOoph40icKYKN+s3fOE4KyIFY/UeELScrFsv1/m22i\nlIigVsALXePg0xD/dJf58vbM7tn4o5OP+pNZ7V7nxk8rzPidP6idd3vfU1WDlWpy\nE56UzvunAgMBAAECggEAcq7lHNAHdHLgT8yrY41x/AwPryNGO/9JNW7SGVKAdjoU\ntyaLZHAEmXynLk+R28/YFMA8H4Yd9m9OlrYhVjRZFM4p+5vxP/7YHPB7cPUsfcda\nDZxR8PX25JVYf/vtb16V0ERLnKd62qCEwC/lr2A2WHQwXJLrHeAtmZzBJYUCJ5Xj\nDv1ZhyFjknswaV0vGXe6njTI6CzMQDTGysoagpCCo7RWgzjLREg2BGWd2UQpY4AW\nnYAP4QNt82UMQbgIqsEMj64mzS9Q+o1P84J1naSP5sCI22LeFRp6iezZc+D8EH/5\nRNONGSNWl3g6bsvN1VywYwjWn+waD3XAjXUu+peUgQKBgQDDu1QP28oSMKivHdfo\nkQ1HrTNBRc9eWeAMZFuIbbPLN8rdEibpOm3DwTqithnahqS0NLOsBnXNtuLw1Qr/\nzmOzn0yDO5XG8dlKr9vqWeBLdcRydLJBZwqEzWf4JwwwgfK3rItRaIbnAxnGUTS5\nSrrhNfBAIGS9jx5X2kvLC7hFQQKBgQDDBIrpLTIjRDloWZcu03z9Bhb8jQCyGb5C\n4MYs+duCnQIdNq/+maPspJzbVmF4b6S1zIPweI3fMvMeqRTbuf+drpElst1buFTO\nP0UMMn4V+4qGIOOkIy5JIKwR8sJD9tNDUPtxuDEotTB9IyWx6pdmCFz5v/bggDCu\nreoqflL+5wKBgQCDvb+L2QS+j4/KJk0flRoaJ2K7SVCVEesyjA3r2uLMImZhvAkC\nrDgbLSDZSbZHFp8fR+WzILoD11gSf2Ki4PjMeqkWH3HlcP0vPwTHTO0h/UdXPmKI\nkOFMl7CmHyoeMCj9JZ60EaXTMYwUpq3VFY6JbTOjBeqoh/8FZMHlDaNewQKBgCHg\nECEg8KyflTlDFrfTlMp+3E9STuShBCOp18LIRBEUJOHeNgQLvCXHElgnURcSjZHm\nzKRgzIQQ3Zpd1Hm2fWhuglgCEeF0y4ZoBx5vRueaoh1aaTCBy/B39GvJt2UG4vu2\nfXbrf96KWrnh+RJGpbXbjgr0BXZJzisJmrt25gPRAoGBAI3c+INpQXwrE+LBzCPu\nLwIVvkm5NpeIlKQtDNrqG1QvUhqyZ2/Xitc4FyiccW7WHxkGKGZyj7GbmpqEOnyY\niVku0LSftZgycet2uMdp0HaVAgi5S6aVf5yN0U/8R5ToxcbuEfqwrBIyRgse8lx3\nNNSvLxPAempmiFPSk9AtobYV\n-----END PRIVATE KEY-----" - }, - "type": "kubernetes.io/tls" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "cert-b12464ec431576239dd9cc2545d528f6cbdbd988cf076323" - }, - "stringData": { - "tls.crt": "-----BEGIN CERTIFICATE-----\nMIIFeDCCBGCgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyQwDQYJKoZIhvcNAQEL\nBQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM\nCUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY\nMBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u\nZ2hxLmNvbTAeFw0yMTAxMjAxNTA0NDVaFw0yMjAxMjAxNTA0NDVaMIGQMQswCQYD\nVQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx\nEDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFjAUBgNVBAMMDW10\nbHMtY29uc3VtZXIxHTAbBgkqhkiG9w0BCQEWDnN0dUBrb25naHEuY29tMIICIjAN\nBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1/+83/YNiEVKYvcuVwYGve6afsg1\nBYCn1+E9Uwgh0uwAenT/DKB8NhqoVxc7cZ2HaTI146IGmFICmctlTWvLPLglHmTo\nbyOUV6tIJAjvzyEOpC458hLGgbv8mhGXJWPxBVu7Wy6Hapz2bk0cEscfL7PHKaRu\n3D6r8/zbhhWAqe4EIt+NVYT6baaYBs7bPZQXs/sluKI+DNYuDeaAmoSuCc4ein6z\n0xDqCSMmPebzjns03ttB29vWL3eYY9dvgoCd+CPhXT/C4CHtvKbH+hOQYDtVF6MO\n1mmABAQTQWMR/00+QI0xtvuXtEPurla5dA0TN6ddCTOOcILKx62z5oc3Kqr+nHHa\n71zNzARUVaZ2vy1pRVr0DZgB7KqcFXhy/oy8IpmxUR1ASBDZl6B6RKrdQwvgLgmn\n3M/roNLAU+3nz4itpt/zf+X0suwdthrflic1R68z1SlYbyoGARWkZ/pOl6kLNVK2\nOsqQuICaajnW7t1oDd7z1+3hm+uoryDwvG6f3T9ZvWjKXYcKg7b+BjbFdahbDywD\nPgnhSz9AaoVWhR+GHIPrjRClMpEkra/yGJFvH3UpXhgg9d0DrLZE51Z75a9SvnAj\nvdLuNhx4bJbwLBgNGsJMkupzBrw4iCfbKFcBbP8o0Xjtarj7T/mkWuQ1GjWqfyrD\n55NecBPNw5C9BR0CAwEAAaOBxTCBwjAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQE\nAwIFoDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgQ2xpZW50IENl\ncnRpZmljYXRlMB0GA1UdDgQWBBSV3F+eicU8SVT4LcDJ6eMzP0todzAfBgNVHSME\nGDAWgBR2ySl/TAlFDGO3NAVlyJaZR+XZtzAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0l\nBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4IBAQB5L0OZ\nWELG9Pw6Ol1BsZYgpLR4PGNBB9dKm/9dd+q+ohZVFCfXcjZ3YOU1vh/HHQrALRNY\nI58JxcVCOx/qIW2uA0iSCqIT0sNb9cJLxfZf7X+BzPPPnu0ugUJp7GzLNnHitrLC\nXb1nmmefwgraNzp+a5IrR8RcQG1mYDuS+2HK/rybo22XcCxhob8OiDEn8+ytkKyQ\nIpmrf9D+/68/ih6az0w1aakASMmFe8z/p6VgVQkCySCWWFG525BRdGmSImqVZ4xa\naQFN3L+oN+JJcCFTthLOAYo32JH+xLMz7PokzSL84g3b68h59hXDoMSwB10GthL5\nT8tqV6i5miKWwvfZ\n-----END CERTIFICATE-----", - "tls.key": "-----BEGIN RSA PRIVATE KEY-----\n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\n-----END RSA PRIVATE KEY-----" - }, - "type": "kubernetes.io/tls" -}{ - "apiVersion": "configuration.konghq.com/v1", - "consumerGroups": [ - "example-consumer-group" - ], - "credentials": [ - "key-auth-example-user", - "jwt-auth-example-user", - "basic-auth-example-user", - "acl-group-example-user", - "mtls-auth-example-user" - ], - "custom_id": "1234567890", - "kind": "KongConsumer", - "metadata": { - "annotations": { - "konghq.com/plugins": "example-user-rate-limiting-advanced", - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-user" - }, - "username": "example-user" -}{ - "apiVersion": "configuration.konghq.com/v1beta1", - "kind": "KongConsumerGroup", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-consumer-group" - } -} \ No newline at end of file diff --git a/kong2kic/testdata/kicv2_ingress/output-expected.yaml b/kong2kic/testdata/kicv2_ingress/output-expected.yaml deleted file mode 100644 index a6b26955d..000000000 --- a/kong2kic/testdata/kicv2_ingress/output-expected.yaml +++ /dev/null @@ -1,737 +0,0 @@ -apiVersion: configuration.konghq.com/v1 -kind: KongIngress -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service-upstream -upstream: - algorithm: round-robin - hash_fallback: none - hash_on: none - hash_on_cookie_path: / - healthchecks: - active: - concurrency: 10 - headers: - x-another-header: - - bla - x-my-header: - - foo - - bar - healthy: - http_statuses: - - 200 - - 302 - interval: 0 - successes: 0 - http_path: / - https_sni: example.com - https_verify_certificate: true - timeout: 1 - type: http - unhealthy: - http_failures: 0 - http_statuses: - - 429 - - 404 - - 500 - - 501 - - 502 - - 503 - - 504 - - 505 - interval: 0 - tcp_failures: 0 - timeouts: 0 - passive: - healthy: - http_statuses: - - 200 - - 201 - - 202 - - 203 - - 204 - - 205 - - 206 - - 207 - - 208 - - 226 - - 300 - - 301 - - 302 - - 303 - - 304 - - 305 - - 306 - - 307 - - 308 - successes: 0 - type: http - unhealthy: - http_failures: 0 - http_statuses: - - 429 - - 500 - - 503 - tcp_failures: 0 - timeouts: 0 - threshold: 0 - host_header: example.com - slots: 10000 ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_client_headers: false - identifier: consumer - limit: - - 5 - namespace: example_namespace - strategy: local - sync_rate: -1 - window_size: - - 30 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service-rate-limiting-advanced -plugin: rate-limiting-advanced ---- -apiVersion: configuration.konghq.com/v1 -config: - aws_key: my_key - aws_region: us-west-2 - aws_secret: my_secret - function_name: my_function -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long9344b5559f -plugin: aws-lambda ---- -apiVersion: configuration.konghq.com/v1 -config: - credentials: true - exposed_headers: - - X-My-Header - headers: - - Authorization - max_age: 3600 - methods: - - GET - - POST - origins: - - example.com -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longfdeaa51f90 -plugin: cors ---- -apiVersion: configuration.konghq.com/v1 -config: - path: /var/log/kong/kong.log - reopen: true -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long3b4b1fae8e -plugin: file-log ---- -apiVersion: configuration.konghq.com/v1 -config: - content_type: application/json - http_endpoint: http://example.com/logs - keepalive: 60000 - method: POST - queue_size: 1000 - retry_count: 10 - timeout: 10000 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long59030a424c -plugin: http-log ---- -apiVersion: configuration.konghq.com/v1 -config: - allow: - - 192.168.0.1/24 - deny: - - 192.168.0.2/32 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longb44edd01cf -plugin: ip-restriction ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_client_headers: false - identifier: consumer - limit: - - 5 - namespace: example_namespace - strategy: local - sync_rate: -1 - window_size: - - 30 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longef35b834c6 -plugin: rate-limiting-advanced ---- -apiVersion: configuration.konghq.com/v1 -config: - message: Forbidden - status_code: 403 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longb2c08ebc54 -plugin: request-termination ---- -apiVersion: configuration.konghq.com/v1 -config: - limits: - limit_name: - minute: 10 - policy: local -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longc400f1ab11 -plugin: response-ratelimiting ---- -apiVersion: configuration.konghq.com/v1 -config: - host: example.com - port: 1234 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long47f9f5054d -plugin: tcp-log ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_credentials: false -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long26f9714514 -plugin: basic-auth ---- -apiVersion: configuration.konghq.com/v1 -config: - anonymous: null - claims_to_verify: - - exp - - nbf - header_names: - - Authorization - key_claim_name: kid - maximum_expiration: 3600 - run_on_preflight: true - secret_is_base64: false - uri_param_names: - - token -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long0239c8f63e -plugin: jwt ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_credentials: false - key_in_body: false - key_names: - - apikey - run_on_preflight: true -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long5494737f3e -plugin: key-auth ---- -apiVersion: configuration.konghq.com/v1 -config: - ca_certificates: - - cce8c384-721f-4f58-85dd-50834e3e733a - revocation_check_mode: SKIP - skip_consumer_lookup: false -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long89ae2d2b5d -plugin: mtls-auth ---- -apiVersion: configuration.konghq.com/v1 -config: - allow: - - admin -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longb2440ac898 -plugin: acl ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_client_headers: false - identifier: consumer - limit: - - 5 - namespace: example_namespace - strategy: local - sync_rate: -1 - window_size: - - 30 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-user-rate-limiting-advanced -plugin: rate-limiting-advanced ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - konghq.com/headers.x-another-header: first-header-value,second-header-value - konghq.com/headers.x-my-header: ~*foos?bar$ - konghq.com/https-redirect-status-code: "302" - konghq.com/methods: GET,POST - konghq.com/plugins: example-service--route-thisisaveryvery-long9344b5559f,example-service--route-thisisaveryvery-longfdeaa51f90,example-service--route-thisisaveryvery-long3b4b1fae8e,example-service--route-thisisaveryvery-long59030a424c,example-service--route-thisisaveryvery-longb44edd01cf,example-service--route-thisisaveryvery-longef35b834c6,example-service--route-thisisaveryvery-longb2c08ebc54,example-service--route-thisisaveryvery-longc400f1ab11,example-service--route-thisisaveryvery-long47f9f5054d,example-service--route-thisisaveryvery-long26f9714514,example-service--route-thisisaveryvery-long0239c8f63e,example-service--route-thisisaveryvery-long5494737f3e,example-service--route-thisisaveryvery-long89ae2d2b5d,example-service--route-thisisaveryvery-longb2440ac898 - konghq.com/preserve-host: "true" - konghq.com/protocols: http,https - konghq.com/regex-priority: "1" - konghq.com/snis: example.com - konghq.com/strip-path: "false" - name: example-service--route-thisisaveryvery-long2093a020ca -spec: - ingressClassName: kong - rules: - - host: example.com - http: - paths: - - backend: - service: - name: example-service - port: - number: 80 - path: /~/v1/example/?$ - pathType: ImplementationSpecific - - backend: - service: - name: example-service - port: - number: 80 - path: /v1/another-example - pathType: ImplementationSpecific - - backend: - service: - name: example-service - port: - number: 80 - path: /v1/yet-another-example - pathType: ImplementationSpecific - - host: another-example.com - http: - paths: - - backend: - service: - name: example-service - port: - number: 80 - path: /~/v1/example/?$ - pathType: ImplementationSpecific - - backend: - service: - name: example-service - port: - number: 80 - path: /v1/another-example - pathType: ImplementationSpecific - - backend: - service: - name: example-service - port: - number: 80 - path: /v1/yet-another-example - pathType: ImplementationSpecific - - host: yet-another-example.com - http: - paths: - - backend: - service: - name: example-service - port: - number: 80 - path: /~/v1/example/?$ - pathType: ImplementationSpecific - - backend: - service: - name: example-service - port: - number: 80 - path: /v1/another-example - pathType: ImplementationSpecific - - backend: - service: - name: example-service - port: - number: 80 - path: /v1/yet-another-example - pathType: ImplementationSpecific ---- -apiVersion: v1 -kind: Service -metadata: - annotations: - konghq.com/connect-timeout: "5000" - konghq.com/override: example-service-upstream - konghq.com/path: /v1 - konghq.com/plugins: example-service-rate-limiting-advanced - konghq.com/protocol: http - konghq.com/read-timeout: "60000" - konghq.com/retries: "5" - konghq.com/write-timeout: "60000" - name: example-service -spec: - ports: - - port: 80 - protocol: TCP - targetPort: 80 - selector: - app: example-service ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: key-auth-example-user -stringData: - key: my_api_key - kongCredType: key-auth ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: jwt-auth-example-user -stringData: - algorithm: HS256 - key: my_jwt_secret - kongCredType: jwt - rsa_public_key: |- - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxXzYS5yESbekTF3xLiQX - ZZZfXt0S/nzFp3f2Oux3W7/ydvZ8XSd8+s+wm5oqEcSV9n+5n3ENZbt1A/wgnGI3 - oWrv0yRB9HugzTIGPpI1AQv9Z4p8E44RrB74/uTxYwb9+4yvpuz/fzTt3Gz+Kzc4 - 4fGGq8VpGMFj6AE65ZcOAHHUJe4VuoreBXLYDJcHl2WPIdNKDGscFjElDneLRhWQ - DfxekDJIQMWCjyBEXacfP6cc9U8Qld6TuVcwi1P2xb8tBDD4MIFL/psfzUhfv1Lw - O/XZEffJxCqkQn7dsCYy3wpaTjb6XmJ5j0Dbml4f0Bv40Y1mjlAf7C662Mbuguf6 - ewIDAQAB - -----END PUBLIC KEY----- - secret: my_secret_key ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: basic-auth-example-user -stringData: - kongCredType: basic-auth - password: my_basic_password - username: my_basic_user ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: acl-group-example-user -stringData: - group: acl_group - kongCredType: acl ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: mtls-auth-example-user -stringData: - id: cce8c384-721f-4f58-85dd-50834e3e733a - kongCredType: mtls-auth - subject_name: example-user@example.com -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: ca-cert-a672ab52d2341203bd70116b456413d7ac3ffc162abbf -stringData: - ca.crt: | - -----BEGIN CERTIFICATE----- - MIIBfDCCASKgAwIBAgIRAJqcZC1VSvSQLMN1+7yAeswwCgYIKoZIzj0EAwIwHDEa - MBgGA1UEAxMRRGVtbyBLb25nIFJvb3QgQ0EwHhcNMjIwNjEzMTMzNzMzWhcNMjcw - NjEzMTkzNzMzWjAcMRowGAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTBZMBMGByqG - SM49AgEGCCqGSM49AwEHA0IABOGR89IyhreSHRAi6wp9a5DBIDp4YYSdWzuEdlNx - 7pX1G4T7x68xUXJZXRUPFyT8Xzn5KwCJm8RVT+nAhrsUx6SjRTBDMA4GA1UdDwEB - /wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBQ9CUiOPhjp7KD2 - ScRDxX4IzDOrNzAKBggqhkjOPQQDAgNIADBFAiEAw6Dov0c0L++1W9VufAfSMdNR - PSDfPU0MiUiG59/VIBICIEFn/6c5eQc3hUUBL74/RmNT2b1zxBmp7RiPXJAnAAwJ - -----END CERTIFICATE----- - ca.digest: f1baffe9fe9cf8497e38a4271d67fab44423678b7e7c0f677a50f37c113d81b5 -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: ca-cert-a4f087c2ee00e6d43cfb4f6884fc1e79f7e6e08e84471 -stringData: - ca.crt: | - -----BEGIN CERTIFICATE----- - MIIBqTCCAVCgAwIBAgIQb5LqGa9gS3+Mc2ntWfSoJjAKBggqhkjOPQQDAjAcMRow - GAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTAeFw0yMjA2MTMxMzM5MTVaFw0yMzA2 - MTMxOTM5MTVaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBSb290IEludGVybWVkaWF0 - ZTEgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQImvnSuvXkGy88lvx8a7of - e0MEMRI2siVvybvWXNpeXXlixgaq7weJ7pewf3HywfO68Va6kn8ehWh7s0D7SLHM - o2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4E - FgQUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwHwYDVR0jBBgwFoAUPQlIjj4Y6eyg9knE - Q8V+CMwzqzcwCgYIKoZIzj0EAwIDRwAwRAIgNZ+JPA1OqF5DsPapAZ2YsUOgIpn3 - ZbQuYKCAV0SD4EcCIFnfA5rWrc1AgtUw5inJQqJQRNgoPuC14vACqI48BiRl - -----END CERTIFICATE----- - ca.digest: dbef7ed285fb292e24f84ffba93c48d92fa322387d85469c460c655abedd5308 -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: ca-cert-6b095c7ff377b01252a4dfec59c582fe32934fa7ed0cf -stringData: - ca.crt: | - -----BEGIN CERTIFICATE----- - MIIBujCCAV+gAwIBAgIRAMkGpj7WZf+2RFE/q7ZhejEwCgYIKoZIzj0EAwIwKjEo - MCYGA1UEAxMfRGVtbyBLb25nIFJvb3QgSW50ZXJtZWRpYXRlMSBDQTAeFw0yMjA2 - MTMxMzQwNTFaFw0yMjEyMTMwNDQwNTFaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBS - b290IEludGVybWVkaWF0ZTIgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQB - my/zhZ3F2HvHFqtQzuD3lXX8SeYakxiBQvaGkGSLKD67N3vh7iC2rTSdj/vAs8ws - Y9X+mXzS6GDKC8PbSX6xo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgw - BgEB/wIBADAdBgNVHQ4EFgQURwCm53YPStZoAMfnVyknH4IgZa4wHwYDVR0jBBgw - FoAUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwCgYIKoZIzj0EAwIDSQAwRgIhAN1pkUKc - azM4PiXOnkILB2KBDIF4XpHf+4ThDMODzXP8AiEA45KXA3qMrRPQV1oBfWZ3hLgX - gxUhveuHBXMWnzUbn6U= - -----END CERTIFICATE----- - ca.digest: 45b2b6dd9d4102955b1b1e4b540e677f140521462ed4f22fa5a713863ca84600 -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: cert-0ee0e1584c8637facac95bd5fce315367dee124c0086d41e -stringData: - tls.crt: |- - -----BEGIN CERTIFICATE----- - MIIECTCCAvGgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyAwDQYJKoZIhvcNAQEL - BQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM - CUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY - MBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u - Z2hxLmNvbTAeFw0yMTAxMTUxMTE5NDNaFw0yMjA1MzAxMTE5NDNaMIGRMQswCQYD - VQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx - EDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFzAVBgNVBAMMDnBy - b3h5LmtvbmcubGFuMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29uZ2hxLmNvbTCCASIw - DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJUbKiqoCK1BTNk/7l42n6ukyTEu - eLyB23e/90PzT/oz8wZzgwTodzbFAS2VtFr1EKqFzor0DrXp9CLnebOdiAR3I6LD - /WY/x0KW3lx3F35fGiUOSLPTH8zeiDTMx11CcKDxesA+M2/s5q0igkOQ4z4w3voz - m5a52IcQTSA8K5knNU1qUZBLpc+khxFcaheEK1jsISJJhcdizZBfGdk8S1vpyj5F - uCZ7oaRvNA6imHjSJwpgo36zd84TgrIgVj9R4QtJysWy/X+bbaKUiKBWwAtd4+DT - EP90l/ny9szu2fijk4/6k1ntXufGTyvM+J0/qJ13e99TVYOVanITnpTO+6cCAwEA - AaNWMFQwHwYDVR0jBBgwFoAUdskpf0wJRQxjtzQFZciWmUfl2bcwCQYDVR0TBAIw - ADALBgNVHQ8EBAMCBPAwGQYDVR0RBBIwEIIOcHJveHkua29uZy5sYW4wDQYJKoZI - hvcNAQELBQADggEBAJVrTWQRQzNtypa9OXFYADm8Fay1VMop3BY2kh0tfYgQEJ/4 - pJUj6CaszQZ/Aix6LaPnXFcoPCDqqv00mgju86PMamr/zA9USXk8eTmzJkp5RklS - GdqiXboqESiQVvaNz3kdW7wgNz4FwaGCzkEi/dcc2LdtzLpWizx+TlxMMqjonUUM - ovZgZo+OlhWRsDVT/qy5SFtA0vlVNtdBr2egXb1H7J8UDC+fax/iKa7+fBUHZOO9 - Fk9U8bxgfQ+jPIVVL8CfAtR68Sos7NpWH0S2emqZRnQvf0MSNdkTQKWn4qR9sckj - Ewxs5FbrMmgCOgwk1PtgRmdP3RME0HwK/B03saQ= - -----END CERTIFICATE----- - tls.key: |- - -----BEGIN PRIVATE KEY----- - MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCVGyoqqAitQUzZ - P+5eNp+rpMkxLni8gdt3v/dD80/6M/MGc4ME6Hc2xQEtlbRa9RCqhc6K9A616fQi - 53mznYgEdyOiw/1mP8dClt5cdxd+XxolDkiz0x/M3og0zMddQnCg8XrAPjNv7Oat - IoJDkOM+MN76M5uWudiHEE0gPCuZJzVNalGQS6XPpIcRXGoXhCtY7CEiSYXHYs2Q - XxnZPEtb6co+Rbgme6GkbzQOoph40icKYKN+s3fOE4KyIFY/UeELScrFsv1/m22i - lIigVsALXePg0xD/dJf58vbM7tn4o5OP+pNZ7V7nxk8rzPidP6idd3vfU1WDlWpy - E56UzvunAgMBAAECggEAcq7lHNAHdHLgT8yrY41x/AwPryNGO/9JNW7SGVKAdjoU - tyaLZHAEmXynLk+R28/YFMA8H4Yd9m9OlrYhVjRZFM4p+5vxP/7YHPB7cPUsfcda - DZxR8PX25JVYf/vtb16V0ERLnKd62qCEwC/lr2A2WHQwXJLrHeAtmZzBJYUCJ5Xj - Dv1ZhyFjknswaV0vGXe6njTI6CzMQDTGysoagpCCo7RWgzjLREg2BGWd2UQpY4AW - nYAP4QNt82UMQbgIqsEMj64mzS9Q+o1P84J1naSP5sCI22LeFRp6iezZc+D8EH/5 - RNONGSNWl3g6bsvN1VywYwjWn+waD3XAjXUu+peUgQKBgQDDu1QP28oSMKivHdfo - kQ1HrTNBRc9eWeAMZFuIbbPLN8rdEibpOm3DwTqithnahqS0NLOsBnXNtuLw1Qr/ - zmOzn0yDO5XG8dlKr9vqWeBLdcRydLJBZwqEzWf4JwwwgfK3rItRaIbnAxnGUTS5 - SrrhNfBAIGS9jx5X2kvLC7hFQQKBgQDDBIrpLTIjRDloWZcu03z9Bhb8jQCyGb5C - 4MYs+duCnQIdNq/+maPspJzbVmF4b6S1zIPweI3fMvMeqRTbuf+drpElst1buFTO - P0UMMn4V+4qGIOOkIy5JIKwR8sJD9tNDUPtxuDEotTB9IyWx6pdmCFz5v/bggDCu - reoqflL+5wKBgQCDvb+L2QS+j4/KJk0flRoaJ2K7SVCVEesyjA3r2uLMImZhvAkC - rDgbLSDZSbZHFp8fR+WzILoD11gSf2Ki4PjMeqkWH3HlcP0vPwTHTO0h/UdXPmKI - kOFMl7CmHyoeMCj9JZ60EaXTMYwUpq3VFY6JbTOjBeqoh/8FZMHlDaNewQKBgCHg - ECEg8KyflTlDFrfTlMp+3E9STuShBCOp18LIRBEUJOHeNgQLvCXHElgnURcSjZHm - zKRgzIQQ3Zpd1Hm2fWhuglgCEeF0y4ZoBx5vRueaoh1aaTCBy/B39GvJt2UG4vu2 - fXbrf96KWrnh+RJGpbXbjgr0BXZJzisJmrt25gPRAoGBAI3c+INpQXwrE+LBzCPu - LwIVvkm5NpeIlKQtDNrqG1QvUhqyZ2/Xitc4FyiccW7WHxkGKGZyj7GbmpqEOnyY - iVku0LSftZgycet2uMdp0HaVAgi5S6aVf5yN0U/8R5ToxcbuEfqwrBIyRgse8lx3 - NNSvLxPAempmiFPSk9AtobYV - -----END PRIVATE KEY----- -type: kubernetes.io/tls ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: cert-b12464ec431576239dd9cc2545d528f6cbdbd988cf076323 -stringData: - tls.crt: |- - -----BEGIN CERTIFICATE----- - MIIFeDCCBGCgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyQwDQYJKoZIhvcNAQEL - BQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM - CUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY - MBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u - Z2hxLmNvbTAeFw0yMTAxMjAxNTA0NDVaFw0yMjAxMjAxNTA0NDVaMIGQMQswCQYD - VQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx - EDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFjAUBgNVBAMMDW10 - bHMtY29uc3VtZXIxHTAbBgkqhkiG9w0BCQEWDnN0dUBrb25naHEuY29tMIICIjAN - BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1/+83/YNiEVKYvcuVwYGve6afsg1 - BYCn1+E9Uwgh0uwAenT/DKB8NhqoVxc7cZ2HaTI146IGmFICmctlTWvLPLglHmTo - byOUV6tIJAjvzyEOpC458hLGgbv8mhGXJWPxBVu7Wy6Hapz2bk0cEscfL7PHKaRu - 3D6r8/zbhhWAqe4EIt+NVYT6baaYBs7bPZQXs/sluKI+DNYuDeaAmoSuCc4ein6z - 0xDqCSMmPebzjns03ttB29vWL3eYY9dvgoCd+CPhXT/C4CHtvKbH+hOQYDtVF6MO - 1mmABAQTQWMR/00+QI0xtvuXtEPurla5dA0TN6ddCTOOcILKx62z5oc3Kqr+nHHa - 71zNzARUVaZ2vy1pRVr0DZgB7KqcFXhy/oy8IpmxUR1ASBDZl6B6RKrdQwvgLgmn - 3M/roNLAU+3nz4itpt/zf+X0suwdthrflic1R68z1SlYbyoGARWkZ/pOl6kLNVK2 - OsqQuICaajnW7t1oDd7z1+3hm+uoryDwvG6f3T9ZvWjKXYcKg7b+BjbFdahbDywD - PgnhSz9AaoVWhR+GHIPrjRClMpEkra/yGJFvH3UpXhgg9d0DrLZE51Z75a9SvnAj - vdLuNhx4bJbwLBgNGsJMkupzBrw4iCfbKFcBbP8o0Xjtarj7T/mkWuQ1GjWqfyrD - 55NecBPNw5C9BR0CAwEAAaOBxTCBwjAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQE - AwIFoDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgQ2xpZW50IENl - cnRpZmljYXRlMB0GA1UdDgQWBBSV3F+eicU8SVT4LcDJ6eMzP0todzAfBgNVHSME - GDAWgBR2ySl/TAlFDGO3NAVlyJaZR+XZtzAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0l - BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4IBAQB5L0OZ - WELG9Pw6Ol1BsZYgpLR4PGNBB9dKm/9dd+q+ohZVFCfXcjZ3YOU1vh/HHQrALRNY - I58JxcVCOx/qIW2uA0iSCqIT0sNb9cJLxfZf7X+BzPPPnu0ugUJp7GzLNnHitrLC - Xb1nmmefwgraNzp+a5IrR8RcQG1mYDuS+2HK/rybo22XcCxhob8OiDEn8+ytkKyQ - Ipmrf9D+/68/ih6az0w1aakASMmFe8z/p6VgVQkCySCWWFG525BRdGmSImqVZ4xa - aQFN3L+oN+JJcCFTthLOAYo32JH+xLMz7PokzSL84g3b68h59hXDoMSwB10GthL5 - T8tqV6i5miKWwvfZ - -----END CERTIFICATE----- - tls.key: |- - -----BEGIN RSA PRIVATE KEY----- - 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 - -----END RSA PRIVATE KEY----- -type: kubernetes.io/tls ---- -apiVersion: configuration.konghq.com/v1 -consumerGroups: -- example-consumer-group -credentials: -- key-auth-example-user -- jwt-auth-example-user -- basic-auth-example-user -- acl-group-example-user -- mtls-auth-example-user -custom_id: "1234567890" -kind: KongConsumer -metadata: - annotations: - konghq.com/plugins: example-user-rate-limiting-advanced - kubernetes.io/ingress.class: kong - name: example-user -username: example-user ---- -apiVersion: configuration.konghq.com/v1beta1 -kind: KongConsumerGroup -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-consumer-group ---- diff --git a/kong2kic/testdata/kicv3_gateway/output-expected.json b/kong2kic/testdata/kicv3_gateway/output-expected.json deleted file mode 100644 index 3be1f7ce6..000000000 --- a/kong2kic/testdata/kicv3_gateway/output-expected.json +++ /dev/null @@ -1,1486 +0,0 @@ -{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_client_headers": false, - "identifier": "consumer", - "limit": [ - 5 - ], - "namespace": "example_namespace", - "strategy": "local", - "sync_rate": -1, - "window_size": [ - 30 - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service-rate-limiting-advanced" - }, - "plugin": "rate-limiting-advanced" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "aws_key": "my_key", - "aws_region": "us-west-2", - "aws_secret": "my_secret", - "function_name": "my_function" - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "plugin": "aws-lambda" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "credentials": true, - "exposed_headers": [ - "X-My-Header" - ], - "headers": [ - "Authorization" - ], - "max_age": 3600, - "methods": [ - "GET", - "POST" - ], - "origins": [ - "example.com" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "plugin": "cors" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "path": "/var/log/kong/kong.log", - "reopen": true - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "plugin": "file-log" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "content_type": "application/json", - "http_endpoint": "http://example.com/logs", - "keepalive": 60000, - "method": "POST", - "queue_size": 1000, - "retry_count": 10, - "timeout": 10000 - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "plugin": "http-log" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "allow": [ - "192.168.0.1/24" - ], - "deny": [ - "192.168.0.2/32" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "plugin": "ip-restriction" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_client_headers": false, - "identifier": "consumer", - "limit": [ - 5 - ], - "namespace": "example_namespace", - "strategy": "local", - "sync_rate": -1, - "window_size": [ - 30 - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "plugin": "rate-limiting-advanced" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "message": "Forbidden", - "status_code": 403 - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "plugin": "request-termination" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "limits": { - "limit_name": { - "minute": 10 - } - }, - "policy": "local" - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "plugin": "response-ratelimiting" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "host": "example.com", - "port": 1234 - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "plugin": "tcp-log" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_credentials": false - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "plugin": "basic-auth" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "anonymous": null, - "claims_to_verify": [ - "exp", - "nbf" - ], - "header_names": [ - "Authorization" - ], - "key_claim_name": "kid", - "maximum_expiration": 3600, - "run_on_preflight": true, - "secret_is_base64": false, - "uri_param_names": [ - "token" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "plugin": "jwt" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_credentials": false, - "key_in_body": false, - "key_names": [ - "apikey" - ], - "run_on_preflight": true - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "plugin": "key-auth" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "ca_certificates": [ - "cce8c384-721f-4f58-85dd-50834e3e733a" - ], - "revocation_check_mode": "SKIP", - "skip_consumer_lookup": false - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "plugin": "mtls-auth" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "allow": [ - "admin" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "plugin": "acl" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_client_headers": false, - "identifier": "consumer", - "limit": [ - 5 - ], - "namespace": "example_namespace", - "strategy": "local", - "sync_rate": -1, - "window_size": [ - 30 - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-user-rate-limiting-advanced" - }, - "plugin": "rate-limiting-advanced" -}{ - "apiVersion": "gateway.networking.k8s.io/v1", - "kind": "HTTPRoute", - "metadata": { - "annotations": { - "konghq.com/https-redirect-status-code": "302", - "konghq.com/preserve-host": "true", - "konghq.com/regex-priority": "1", - "konghq.com/snis": "example.com", - "konghq.com/strip-path": "false" - }, - "name": "example-service--route-thisisaveryvery-long2093a020ca" - }, - "spec": { - "hostnames": [ - "example.com", - "another-example.com", - "yet-another-example.com" - ], - "parentRefs": [ - { - "name": "kong" - } - ], - "rules": [ - { - "backendRefs": [ - { - "name": "example-service", - "port": 80 - } - ], - "filters": [ - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "type": "ExtensionRef" - } - ], - "matches": [ - { - "headers": [ - { - "name": "x-another-header", - "type": "Exact", - "value": "first-header-value,second-header-value" - }, - { - "name": "x-my-header", - "type": "RegularExpression", - "value": "foos?bar$" - } - ], - "method": "GET", - "path": { - "type": "RegularExpression", - "value": "/v1/example/?$" - } - } - ] - }, - { - "backendRefs": [ - { - "name": "example-service", - "port": 80 - } - ], - "filters": [ - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "type": "ExtensionRef" - } - ], - "matches": [ - { - "headers": [ - { - "name": "x-another-header", - "type": "Exact", - "value": "first-header-value,second-header-value" - }, - { - "name": "x-my-header", - "type": "RegularExpression", - "value": "foos?bar$" - } - ], - "method": "POST", - "path": { - "type": "RegularExpression", - "value": "/v1/example/?$" - } - } - ] - }, - { - "backendRefs": [ - { - "name": "example-service", - "port": 80 - } - ], - "filters": [ - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "type": "ExtensionRef" - } - ], - "matches": [ - { - "headers": [ - { - "name": "x-another-header", - "type": "Exact", - "value": "first-header-value,second-header-value" - }, - { - "name": "x-my-header", - "type": "RegularExpression", - "value": "foos?bar$" - } - ], - "method": "GET", - "path": { - "type": "PathPrefix", - "value": "/v1/another-example" - } - } - ] - }, - { - "backendRefs": [ - { - "name": "example-service", - "port": 80 - } - ], - "filters": [ - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "type": "ExtensionRef" - } - ], - "matches": [ - { - "headers": [ - { - "name": "x-another-header", - "type": "Exact", - "value": "first-header-value,second-header-value" - }, - { - "name": "x-my-header", - "type": "RegularExpression", - "value": "foos?bar$" - } - ], - "method": "POST", - "path": { - "type": "PathPrefix", - "value": "/v1/another-example" - } - } - ] - }, - { - "backendRefs": [ - { - "name": "example-service", - "port": 80 - } - ], - "filters": [ - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "type": "ExtensionRef" - } - ], - "matches": [ - { - "headers": [ - { - "name": "x-another-header", - "type": "Exact", - "value": "first-header-value,second-header-value" - }, - { - "name": "x-my-header", - "type": "RegularExpression", - "value": "foos?bar$" - } - ], - "method": "GET", - "path": { - "type": "PathPrefix", - "value": "/v1/yet-another-example" - } - } - ] - }, - { - "backendRefs": [ - { - "name": "example-service", - "port": 80 - } - ], - "filters": [ - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "type": "ExtensionRef" - }, - { - "extensionRef": { - "group": "configuration.konghq.com", - "kind": "KongPlugin", - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "type": "ExtensionRef" - } - ], - "matches": [ - { - "headers": [ - { - "name": "x-another-header", - "type": "Exact", - "value": "first-header-value,second-header-value" - }, - { - "name": "x-my-header", - "type": "RegularExpression", - "value": "foos?bar$" - } - ], - "method": "POST", - "path": { - "type": "PathPrefix", - "value": "/v1/yet-another-example" - } - } - ] - } - ] - } -}{ - "apiVersion": "configuration.konghq.com/v1beta1", - "kind": "KongUpstreamPolicy", - "metadata": { - "name": "example-service-upstream" - }, - "spec": { - "algorithm": "round-robin", - "healthchecks": { - "active": { - "concurrency": 10, - "headers": { - "x-another-header": [ - "bla" - ], - "x-my-header": [ - "foo", - "bar" - ] - }, - "healthy": { - "httpStatuses": [ - 200, - 302 - ], - "interval": 0, - "successes": 0 - }, - "httpPath": "/", - "httpsSni": "example.com", - "httpsVerifyCertificate": true, - "timeout": 1, - "type": "http", - "unhealthy": { - "httpFailures": 0, - "httpStatuses": [ - 429, - 404, - 500, - 501, - 502, - 503, - 504, - 505 - ], - "interval": 0, - "tcpFailures": 0, - "timeouts": 0 - } - }, - "passive": { - "healthy": { - "httpStatuses": [ - 200, - 201, - 202, - 203, - 204, - 205, - 206, - 207, - 208, - 226, - 300, - 301, - 302, - 303, - 304, - 305, - 306, - 307, - 308 - ], - "successes": 0 - }, - "type": "http", - "unhealthy": { - "httpFailures": 0, - "httpStatuses": [ - 429, - 500, - 503 - ], - "tcpFailures": 0, - "timeouts": 0 - } - }, - "threshold": 0 - }, - "slots": 10000 - } -}{ - "apiVersion": "v1", - "kind": "Service", - "metadata": { - "annotations": { - "konghq.com/connect-timeout": "5000", - "konghq.com/path": "/v1", - "konghq.com/plugins": "example-service-rate-limiting-advanced", - "konghq.com/protocol": "http", - "konghq.com/read-timeout": "60000", - "konghq.com/retries": "5", - "konghq.com/upstream-policy": "example-service-upstream", - "konghq.com/write-timeout": "60000" - }, - "name": "example-service" - }, - "spec": { - "ports": [ - { - "port": 80, - "protocol": "TCP", - "targetPort": 80 - } - ], - "selector": { - "app": "example-service" - } - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "labels": { - "konghq.com/credential": "key-auth" - }, - "name": "key-auth-example-user" - }, - "stringData": { - "key": "my_api_key" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "labels": { - "konghq.com/credential": "jwt" - }, - "name": "jwt-auth-example-user" - }, - "stringData": { - "algorithm": "HS256", - "key": "my_jwt_secret", - "rsa_public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxXzYS5yESbekTF3xLiQX\nZZZfXt0S/nzFp3f2Oux3W7/ydvZ8XSd8+s+wm5oqEcSV9n+5n3ENZbt1A/wgnGI3\noWrv0yRB9HugzTIGPpI1AQv9Z4p8E44RrB74/uTxYwb9+4yvpuz/fzTt3Gz+Kzc4\n4fGGq8VpGMFj6AE65ZcOAHHUJe4VuoreBXLYDJcHl2WPIdNKDGscFjElDneLRhWQ\nDfxekDJIQMWCjyBEXacfP6cc9U8Qld6TuVcwi1P2xb8tBDD4MIFL/psfzUhfv1Lw\nO/XZEffJxCqkQn7dsCYy3wpaTjb6XmJ5j0Dbml4f0Bv40Y1mjlAf7C662Mbuguf6\newIDAQAB\n-----END PUBLIC KEY-----", - "secret": "my_secret_key" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "labels": { - "konghq.com/credential": "basic-auth" - }, - "name": "basic-auth-example-user" - }, - "stringData": { - "password": "my_basic_password", - "username": "my_basic_user" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "labels": { - "konghq.com/credential": "acl" - }, - "name": "acl-group-example-user" - }, - "stringData": { - "group": "acl_group" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "labels": { - "konghq.com/credential": "mtls-auth" - }, - "name": "mtls-auth-example-user" - }, - "stringData": { - "id": "cce8c384-721f-4f58-85dd-50834e3e733a", - "subject_name": "example-user@example.com" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "ca-cert-a672ab52d2341203bd70116b456413d7ac3ffc162abbf" - }, - "stringData": { - "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIBfDCCASKgAwIBAgIRAJqcZC1VSvSQLMN1+7yAeswwCgYIKoZIzj0EAwIwHDEa\nMBgGA1UEAxMRRGVtbyBLb25nIFJvb3QgQ0EwHhcNMjIwNjEzMTMzNzMzWhcNMjcw\nNjEzMTkzNzMzWjAcMRowGAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTBZMBMGByqG\nSM49AgEGCCqGSM49AwEHA0IABOGR89IyhreSHRAi6wp9a5DBIDp4YYSdWzuEdlNx\n7pX1G4T7x68xUXJZXRUPFyT8Xzn5KwCJm8RVT+nAhrsUx6SjRTBDMA4GA1UdDwEB\n/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBQ9CUiOPhjp7KD2\nScRDxX4IzDOrNzAKBggqhkjOPQQDAgNIADBFAiEAw6Dov0c0L++1W9VufAfSMdNR\nPSDfPU0MiUiG59/VIBICIEFn/6c5eQc3hUUBL74/RmNT2b1zxBmp7RiPXJAnAAwJ\n-----END CERTIFICATE-----\n", - "ca.digest": "f1baffe9fe9cf8497e38a4271d67fab44423678b7e7c0f677a50f37c113d81b5" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "ca-cert-a4f087c2ee00e6d43cfb4f6884fc1e79f7e6e08e84471" - }, - "stringData": { - "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIBqTCCAVCgAwIBAgIQb5LqGa9gS3+Mc2ntWfSoJjAKBggqhkjOPQQDAjAcMRow\nGAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTAeFw0yMjA2MTMxMzM5MTVaFw0yMzA2\nMTMxOTM5MTVaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBSb290IEludGVybWVkaWF0\nZTEgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQImvnSuvXkGy88lvx8a7of\ne0MEMRI2siVvybvWXNpeXXlixgaq7weJ7pewf3HywfO68Va6kn8ehWh7s0D7SLHM\no2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4E\nFgQUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwHwYDVR0jBBgwFoAUPQlIjj4Y6eyg9knE\nQ8V+CMwzqzcwCgYIKoZIzj0EAwIDRwAwRAIgNZ+JPA1OqF5DsPapAZ2YsUOgIpn3\nZbQuYKCAV0SD4EcCIFnfA5rWrc1AgtUw5inJQqJQRNgoPuC14vACqI48BiRl\n-----END CERTIFICATE-----\n", - "ca.digest": "dbef7ed285fb292e24f84ffba93c48d92fa322387d85469c460c655abedd5308" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "ca-cert-6b095c7ff377b01252a4dfec59c582fe32934fa7ed0cf" - }, - "stringData": { - "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIBujCCAV+gAwIBAgIRAMkGpj7WZf+2RFE/q7ZhejEwCgYIKoZIzj0EAwIwKjEo\nMCYGA1UEAxMfRGVtbyBLb25nIFJvb3QgSW50ZXJtZWRpYXRlMSBDQTAeFw0yMjA2\nMTMxMzQwNTFaFw0yMjEyMTMwNDQwNTFaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBS\nb290IEludGVybWVkaWF0ZTIgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQB\nmy/zhZ3F2HvHFqtQzuD3lXX8SeYakxiBQvaGkGSLKD67N3vh7iC2rTSdj/vAs8ws\nY9X+mXzS6GDKC8PbSX6xo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgw\nBgEB/wIBADAdBgNVHQ4EFgQURwCm53YPStZoAMfnVyknH4IgZa4wHwYDVR0jBBgw\nFoAUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwCgYIKoZIzj0EAwIDSQAwRgIhAN1pkUKc\nazM4PiXOnkILB2KBDIF4XpHf+4ThDMODzXP8AiEA45KXA3qMrRPQV1oBfWZ3hLgX\ngxUhveuHBXMWnzUbn6U=\n-----END CERTIFICATE-----\n", - "ca.digest": "45b2b6dd9d4102955b1b1e4b540e677f140521462ed4f22fa5a713863ca84600" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "cert-0ee0e1584c8637facac95bd5fce315367dee124c0086d41e" - }, - "stringData": { - "tls.crt": "-----BEGIN CERTIFICATE-----\nMIIECTCCAvGgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyAwDQYJKoZIhvcNAQEL\nBQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM\nCUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY\nMBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u\nZ2hxLmNvbTAeFw0yMTAxMTUxMTE5NDNaFw0yMjA1MzAxMTE5NDNaMIGRMQswCQYD\nVQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx\nEDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFzAVBgNVBAMMDnBy\nb3h5LmtvbmcubGFuMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29uZ2hxLmNvbTCCASIw\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJUbKiqoCK1BTNk/7l42n6ukyTEu\neLyB23e/90PzT/oz8wZzgwTodzbFAS2VtFr1EKqFzor0DrXp9CLnebOdiAR3I6LD\n/WY/x0KW3lx3F35fGiUOSLPTH8zeiDTMx11CcKDxesA+M2/s5q0igkOQ4z4w3voz\nm5a52IcQTSA8K5knNU1qUZBLpc+khxFcaheEK1jsISJJhcdizZBfGdk8S1vpyj5F\nuCZ7oaRvNA6imHjSJwpgo36zd84TgrIgVj9R4QtJysWy/X+bbaKUiKBWwAtd4+DT\nEP90l/ny9szu2fijk4/6k1ntXufGTyvM+J0/qJ13e99TVYOVanITnpTO+6cCAwEA\nAaNWMFQwHwYDVR0jBBgwFoAUdskpf0wJRQxjtzQFZciWmUfl2bcwCQYDVR0TBAIw\nADALBgNVHQ8EBAMCBPAwGQYDVR0RBBIwEIIOcHJveHkua29uZy5sYW4wDQYJKoZI\nhvcNAQELBQADggEBAJVrTWQRQzNtypa9OXFYADm8Fay1VMop3BY2kh0tfYgQEJ/4\npJUj6CaszQZ/Aix6LaPnXFcoPCDqqv00mgju86PMamr/zA9USXk8eTmzJkp5RklS\nGdqiXboqESiQVvaNz3kdW7wgNz4FwaGCzkEi/dcc2LdtzLpWizx+TlxMMqjonUUM\novZgZo+OlhWRsDVT/qy5SFtA0vlVNtdBr2egXb1H7J8UDC+fax/iKa7+fBUHZOO9\nFk9U8bxgfQ+jPIVVL8CfAtR68Sos7NpWH0S2emqZRnQvf0MSNdkTQKWn4qR9sckj\nEwxs5FbrMmgCOgwk1PtgRmdP3RME0HwK/B03saQ=\n-----END CERTIFICATE-----", - "tls.key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCVGyoqqAitQUzZ\nP+5eNp+rpMkxLni8gdt3v/dD80/6M/MGc4ME6Hc2xQEtlbRa9RCqhc6K9A616fQi\n53mznYgEdyOiw/1mP8dClt5cdxd+XxolDkiz0x/M3og0zMddQnCg8XrAPjNv7Oat\nIoJDkOM+MN76M5uWudiHEE0gPCuZJzVNalGQS6XPpIcRXGoXhCtY7CEiSYXHYs2Q\nXxnZPEtb6co+Rbgme6GkbzQOoph40icKYKN+s3fOE4KyIFY/UeELScrFsv1/m22i\nlIigVsALXePg0xD/dJf58vbM7tn4o5OP+pNZ7V7nxk8rzPidP6idd3vfU1WDlWpy\nE56UzvunAgMBAAECggEAcq7lHNAHdHLgT8yrY41x/AwPryNGO/9JNW7SGVKAdjoU\ntyaLZHAEmXynLk+R28/YFMA8H4Yd9m9OlrYhVjRZFM4p+5vxP/7YHPB7cPUsfcda\nDZxR8PX25JVYf/vtb16V0ERLnKd62qCEwC/lr2A2WHQwXJLrHeAtmZzBJYUCJ5Xj\nDv1ZhyFjknswaV0vGXe6njTI6CzMQDTGysoagpCCo7RWgzjLREg2BGWd2UQpY4AW\nnYAP4QNt82UMQbgIqsEMj64mzS9Q+o1P84J1naSP5sCI22LeFRp6iezZc+D8EH/5\nRNONGSNWl3g6bsvN1VywYwjWn+waD3XAjXUu+peUgQKBgQDDu1QP28oSMKivHdfo\nkQ1HrTNBRc9eWeAMZFuIbbPLN8rdEibpOm3DwTqithnahqS0NLOsBnXNtuLw1Qr/\nzmOzn0yDO5XG8dlKr9vqWeBLdcRydLJBZwqEzWf4JwwwgfK3rItRaIbnAxnGUTS5\nSrrhNfBAIGS9jx5X2kvLC7hFQQKBgQDDBIrpLTIjRDloWZcu03z9Bhb8jQCyGb5C\n4MYs+duCnQIdNq/+maPspJzbVmF4b6S1zIPweI3fMvMeqRTbuf+drpElst1buFTO\nP0UMMn4V+4qGIOOkIy5JIKwR8sJD9tNDUPtxuDEotTB9IyWx6pdmCFz5v/bggDCu\nreoqflL+5wKBgQCDvb+L2QS+j4/KJk0flRoaJ2K7SVCVEesyjA3r2uLMImZhvAkC\nrDgbLSDZSbZHFp8fR+WzILoD11gSf2Ki4PjMeqkWH3HlcP0vPwTHTO0h/UdXPmKI\nkOFMl7CmHyoeMCj9JZ60EaXTMYwUpq3VFY6JbTOjBeqoh/8FZMHlDaNewQKBgCHg\nECEg8KyflTlDFrfTlMp+3E9STuShBCOp18LIRBEUJOHeNgQLvCXHElgnURcSjZHm\nzKRgzIQQ3Zpd1Hm2fWhuglgCEeF0y4ZoBx5vRueaoh1aaTCBy/B39GvJt2UG4vu2\nfXbrf96KWrnh+RJGpbXbjgr0BXZJzisJmrt25gPRAoGBAI3c+INpQXwrE+LBzCPu\nLwIVvkm5NpeIlKQtDNrqG1QvUhqyZ2/Xitc4FyiccW7WHxkGKGZyj7GbmpqEOnyY\niVku0LSftZgycet2uMdp0HaVAgi5S6aVf5yN0U/8R5ToxcbuEfqwrBIyRgse8lx3\nNNSvLxPAempmiFPSk9AtobYV\n-----END PRIVATE KEY-----" - }, - "type": "kubernetes.io/tls" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "cert-b12464ec431576239dd9cc2545d528f6cbdbd988cf076323" - }, - "stringData": { - "tls.crt": "-----BEGIN CERTIFICATE-----\nMIIFeDCCBGCgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyQwDQYJKoZIhvcNAQEL\nBQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM\nCUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY\nMBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u\nZ2hxLmNvbTAeFw0yMTAxMjAxNTA0NDVaFw0yMjAxMjAxNTA0NDVaMIGQMQswCQYD\nVQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx\nEDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFjAUBgNVBAMMDW10\nbHMtY29uc3VtZXIxHTAbBgkqhkiG9w0BCQEWDnN0dUBrb25naHEuY29tMIICIjAN\nBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1/+83/YNiEVKYvcuVwYGve6afsg1\nBYCn1+E9Uwgh0uwAenT/DKB8NhqoVxc7cZ2HaTI146IGmFICmctlTWvLPLglHmTo\nbyOUV6tIJAjvzyEOpC458hLGgbv8mhGXJWPxBVu7Wy6Hapz2bk0cEscfL7PHKaRu\n3D6r8/zbhhWAqe4EIt+NVYT6baaYBs7bPZQXs/sluKI+DNYuDeaAmoSuCc4ein6z\n0xDqCSMmPebzjns03ttB29vWL3eYY9dvgoCd+CPhXT/C4CHtvKbH+hOQYDtVF6MO\n1mmABAQTQWMR/00+QI0xtvuXtEPurla5dA0TN6ddCTOOcILKx62z5oc3Kqr+nHHa\n71zNzARUVaZ2vy1pRVr0DZgB7KqcFXhy/oy8IpmxUR1ASBDZl6B6RKrdQwvgLgmn\n3M/roNLAU+3nz4itpt/zf+X0suwdthrflic1R68z1SlYbyoGARWkZ/pOl6kLNVK2\nOsqQuICaajnW7t1oDd7z1+3hm+uoryDwvG6f3T9ZvWjKXYcKg7b+BjbFdahbDywD\nPgnhSz9AaoVWhR+GHIPrjRClMpEkra/yGJFvH3UpXhgg9d0DrLZE51Z75a9SvnAj\nvdLuNhx4bJbwLBgNGsJMkupzBrw4iCfbKFcBbP8o0Xjtarj7T/mkWuQ1GjWqfyrD\n55NecBPNw5C9BR0CAwEAAaOBxTCBwjAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQE\nAwIFoDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgQ2xpZW50IENl\ncnRpZmljYXRlMB0GA1UdDgQWBBSV3F+eicU8SVT4LcDJ6eMzP0todzAfBgNVHSME\nGDAWgBR2ySl/TAlFDGO3NAVlyJaZR+XZtzAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0l\nBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4IBAQB5L0OZ\nWELG9Pw6Ol1BsZYgpLR4PGNBB9dKm/9dd+q+ohZVFCfXcjZ3YOU1vh/HHQrALRNY\nI58JxcVCOx/qIW2uA0iSCqIT0sNb9cJLxfZf7X+BzPPPnu0ugUJp7GzLNnHitrLC\nXb1nmmefwgraNzp+a5IrR8RcQG1mYDuS+2HK/rybo22XcCxhob8OiDEn8+ytkKyQ\nIpmrf9D+/68/ih6az0w1aakASMmFe8z/p6VgVQkCySCWWFG525BRdGmSImqVZ4xa\naQFN3L+oN+JJcCFTthLOAYo32JH+xLMz7PokzSL84g3b68h59hXDoMSwB10GthL5\nT8tqV6i5miKWwvfZ\n-----END CERTIFICATE-----", - "tls.key": "-----BEGIN RSA PRIVATE KEY-----\n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\n-----END RSA PRIVATE KEY-----" - }, - "type": "kubernetes.io/tls" -}{ - "apiVersion": "configuration.konghq.com/v1", - "consumerGroups": [ - "example-consumer-group" - ], - "credentials": [ - "key-auth-example-user", - "jwt-auth-example-user", - "basic-auth-example-user", - "acl-group-example-user", - "mtls-auth-example-user" - ], - "custom_id": "1234567890", - "kind": "KongConsumer", - "metadata": { - "annotations": { - "konghq.com/plugins": "example-user-rate-limiting-advanced", - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-user" - }, - "username": "example-user" -}{ - "apiVersion": "configuration.konghq.com/v1beta1", - "kind": "KongConsumerGroup", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-consumer-group" - } -} \ No newline at end of file diff --git a/kong2kic/testdata/kicv3_gateway/output-expected.yaml b/kong2kic/testdata/kicv3_gateway/output-expected.yaml deleted file mode 100644 index 9077d04df..000000000 --- a/kong2kic/testdata/kicv3_gateway/output-expected.yaml +++ /dev/null @@ -1,1180 +0,0 @@ -apiVersion: configuration.konghq.com/v1 -config: - hide_client_headers: false - identifier: consumer - limit: - - 5 - namespace: example_namespace - strategy: local - sync_rate: -1 - window_size: - - 30 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service-rate-limiting-advanced -plugin: rate-limiting-advanced ---- -apiVersion: configuration.konghq.com/v1 -config: - aws_key: my_key - aws_region: us-west-2 - aws_secret: my_secret - function_name: my_function -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long9344b5559f -plugin: aws-lambda ---- -apiVersion: configuration.konghq.com/v1 -config: - credentials: true - exposed_headers: - - X-My-Header - headers: - - Authorization - max_age: 3600 - methods: - - GET - - POST - origins: - - example.com -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longfdeaa51f90 -plugin: cors ---- -apiVersion: configuration.konghq.com/v1 -config: - path: /var/log/kong/kong.log - reopen: true -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long3b4b1fae8e -plugin: file-log ---- -apiVersion: configuration.konghq.com/v1 -config: - content_type: application/json - http_endpoint: http://example.com/logs - keepalive: 60000 - method: POST - queue_size: 1000 - retry_count: 10 - timeout: 10000 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long59030a424c -plugin: http-log ---- -apiVersion: configuration.konghq.com/v1 -config: - allow: - - 192.168.0.1/24 - deny: - - 192.168.0.2/32 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longb44edd01cf -plugin: ip-restriction ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_client_headers: false - identifier: consumer - limit: - - 5 - namespace: example_namespace - strategy: local - sync_rate: -1 - window_size: - - 30 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longef35b834c6 -plugin: rate-limiting-advanced ---- -apiVersion: configuration.konghq.com/v1 -config: - message: Forbidden - status_code: 403 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longb2c08ebc54 -plugin: request-termination ---- -apiVersion: configuration.konghq.com/v1 -config: - limits: - limit_name: - minute: 10 - policy: local -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longc400f1ab11 -plugin: response-ratelimiting ---- -apiVersion: configuration.konghq.com/v1 -config: - host: example.com - port: 1234 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long47f9f5054d -plugin: tcp-log ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_credentials: false -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long26f9714514 -plugin: basic-auth ---- -apiVersion: configuration.konghq.com/v1 -config: - anonymous: null - claims_to_verify: - - exp - - nbf - header_names: - - Authorization - key_claim_name: kid - maximum_expiration: 3600 - run_on_preflight: true - secret_is_base64: false - uri_param_names: - - token -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long0239c8f63e -plugin: jwt ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_credentials: false - key_in_body: false - key_names: - - apikey - run_on_preflight: true -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long5494737f3e -plugin: key-auth ---- -apiVersion: configuration.konghq.com/v1 -config: - ca_certificates: - - cce8c384-721f-4f58-85dd-50834e3e733a - revocation_check_mode: SKIP - skip_consumer_lookup: false -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long89ae2d2b5d -plugin: mtls-auth ---- -apiVersion: configuration.konghq.com/v1 -config: - allow: - - admin -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longb2440ac898 -plugin: acl ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_client_headers: false - identifier: consumer - limit: - - 5 - namespace: example_namespace - strategy: local - sync_rate: -1 - window_size: - - 30 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-user-rate-limiting-advanced -plugin: rate-limiting-advanced ---- -apiVersion: gateway.networking.k8s.io/v1 -kind: HTTPRoute -metadata: - annotations: - konghq.com/https-redirect-status-code: "302" - konghq.com/preserve-host: "true" - konghq.com/regex-priority: "1" - konghq.com/snis: example.com - konghq.com/strip-path: "false" - name: example-service--route-thisisaveryvery-long2093a020ca -spec: - hostnames: - - example.com - - another-example.com - - yet-another-example.com - parentRefs: - - name: kong - rules: - - backendRefs: - - name: example-service - port: 80 - filters: - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long9344b5559f - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longfdeaa51f90 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long3b4b1fae8e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long59030a424c - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb44edd01cf - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longef35b834c6 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2c08ebc54 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longc400f1ab11 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long47f9f5054d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long26f9714514 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long0239c8f63e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long5494737f3e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long89ae2d2b5d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2440ac898 - type: ExtensionRef - matches: - - headers: - - name: x-another-header - type: Exact - value: first-header-value,second-header-value - - name: x-my-header - type: RegularExpression - value: foos?bar$ - method: GET - path: - type: RegularExpression - value: /v1/example/?$ - - backendRefs: - - name: example-service - port: 80 - filters: - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long9344b5559f - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longfdeaa51f90 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long3b4b1fae8e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long59030a424c - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb44edd01cf - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longef35b834c6 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2c08ebc54 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longc400f1ab11 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long47f9f5054d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long26f9714514 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long0239c8f63e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long5494737f3e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long89ae2d2b5d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2440ac898 - type: ExtensionRef - matches: - - headers: - - name: x-another-header - type: Exact - value: first-header-value,second-header-value - - name: x-my-header - type: RegularExpression - value: foos?bar$ - method: POST - path: - type: RegularExpression - value: /v1/example/?$ - - backendRefs: - - name: example-service - port: 80 - filters: - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long9344b5559f - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longfdeaa51f90 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long3b4b1fae8e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long59030a424c - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb44edd01cf - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longef35b834c6 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2c08ebc54 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longc400f1ab11 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long47f9f5054d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long26f9714514 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long0239c8f63e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long5494737f3e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long89ae2d2b5d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2440ac898 - type: ExtensionRef - matches: - - headers: - - name: x-another-header - type: Exact - value: first-header-value,second-header-value - - name: x-my-header - type: RegularExpression - value: foos?bar$ - method: GET - path: - type: PathPrefix - value: /v1/another-example - - backendRefs: - - name: example-service - port: 80 - filters: - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long9344b5559f - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longfdeaa51f90 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long3b4b1fae8e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long59030a424c - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb44edd01cf - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longef35b834c6 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2c08ebc54 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longc400f1ab11 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long47f9f5054d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long26f9714514 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long0239c8f63e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long5494737f3e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long89ae2d2b5d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2440ac898 - type: ExtensionRef - matches: - - headers: - - name: x-another-header - type: Exact - value: first-header-value,second-header-value - - name: x-my-header - type: RegularExpression - value: foos?bar$ - method: POST - path: - type: PathPrefix - value: /v1/another-example - - backendRefs: - - name: example-service - port: 80 - filters: - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long9344b5559f - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longfdeaa51f90 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long3b4b1fae8e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long59030a424c - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb44edd01cf - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longef35b834c6 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2c08ebc54 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longc400f1ab11 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long47f9f5054d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long26f9714514 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long0239c8f63e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long5494737f3e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long89ae2d2b5d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2440ac898 - type: ExtensionRef - matches: - - headers: - - name: x-another-header - type: Exact - value: first-header-value,second-header-value - - name: x-my-header - type: RegularExpression - value: foos?bar$ - method: GET - path: - type: PathPrefix - value: /v1/yet-another-example - - backendRefs: - - name: example-service - port: 80 - filters: - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long9344b5559f - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longfdeaa51f90 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long3b4b1fae8e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long59030a424c - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb44edd01cf - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longef35b834c6 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2c08ebc54 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longc400f1ab11 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long47f9f5054d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long26f9714514 - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long0239c8f63e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long5494737f3e - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-long89ae2d2b5d - type: ExtensionRef - - extensionRef: - group: configuration.konghq.com - kind: KongPlugin - name: example-service--route-thisisaveryvery-longb2440ac898 - type: ExtensionRef - matches: - - headers: - - name: x-another-header - type: Exact - value: first-header-value,second-header-value - - name: x-my-header - type: RegularExpression - value: foos?bar$ - method: POST - path: - type: PathPrefix - value: /v1/yet-another-example ---- -apiVersion: configuration.konghq.com/v1beta1 -kind: KongUpstreamPolicy -metadata: - name: example-service-upstream -spec: - algorithm: round-robin - healthchecks: - active: - concurrency: 10 - headers: - x-another-header: - - bla - x-my-header: - - foo - - bar - healthy: - httpStatuses: - - 200 - - 302 - interval: 0 - successes: 0 - httpPath: / - httpsSni: example.com - httpsVerifyCertificate: true - timeout: 1 - type: http - unhealthy: - httpFailures: 0 - httpStatuses: - - 429 - - 404 - - 500 - - 501 - - 502 - - 503 - - 504 - - 505 - interval: 0 - tcpFailures: 0 - timeouts: 0 - passive: - healthy: - httpStatuses: - - 200 - - 201 - - 202 - - 203 - - 204 - - 205 - - 206 - - 207 - - 208 - - 226 - - 300 - - 301 - - 302 - - 303 - - 304 - - 305 - - 306 - - 307 - - 308 - successes: 0 - type: http - unhealthy: - httpFailures: 0 - httpStatuses: - - 429 - - 500 - - 503 - tcpFailures: 0 - timeouts: 0 - threshold: 0 - slots: 10000 ---- -apiVersion: v1 -kind: Service -metadata: - annotations: - konghq.com/connect-timeout: "5000" - konghq.com/path: /v1 - konghq.com/plugins: example-service-rate-limiting-advanced - konghq.com/protocol: http - konghq.com/read-timeout: "60000" - konghq.com/retries: "5" - konghq.com/upstream-policy: example-service-upstream - konghq.com/write-timeout: "60000" - name: example-service -spec: - ports: - - port: 80 - protocol: TCP - targetPort: 80 - selector: - app: example-service ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - labels: - konghq.com/credential: key-auth - name: key-auth-example-user -stringData: - key: my_api_key ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - labels: - konghq.com/credential: jwt - name: jwt-auth-example-user -stringData: - algorithm: HS256 - key: my_jwt_secret - rsa_public_key: |- - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxXzYS5yESbekTF3xLiQX - ZZZfXt0S/nzFp3f2Oux3W7/ydvZ8XSd8+s+wm5oqEcSV9n+5n3ENZbt1A/wgnGI3 - oWrv0yRB9HugzTIGPpI1AQv9Z4p8E44RrB74/uTxYwb9+4yvpuz/fzTt3Gz+Kzc4 - 4fGGq8VpGMFj6AE65ZcOAHHUJe4VuoreBXLYDJcHl2WPIdNKDGscFjElDneLRhWQ - DfxekDJIQMWCjyBEXacfP6cc9U8Qld6TuVcwi1P2xb8tBDD4MIFL/psfzUhfv1Lw - O/XZEffJxCqkQn7dsCYy3wpaTjb6XmJ5j0Dbml4f0Bv40Y1mjlAf7C662Mbuguf6 - ewIDAQAB - -----END PUBLIC KEY----- - secret: my_secret_key ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - labels: - konghq.com/credential: basic-auth - name: basic-auth-example-user -stringData: - password: my_basic_password - username: my_basic_user ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - labels: - konghq.com/credential: acl - name: acl-group-example-user -stringData: - group: acl_group ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - labels: - konghq.com/credential: mtls-auth - name: mtls-auth-example-user -stringData: - id: cce8c384-721f-4f58-85dd-50834e3e733a - subject_name: example-user@example.com -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: ca-cert-a672ab52d2341203bd70116b456413d7ac3ffc162abbf -stringData: - ca.crt: | - -----BEGIN CERTIFICATE----- - MIIBfDCCASKgAwIBAgIRAJqcZC1VSvSQLMN1+7yAeswwCgYIKoZIzj0EAwIwHDEa - MBgGA1UEAxMRRGVtbyBLb25nIFJvb3QgQ0EwHhcNMjIwNjEzMTMzNzMzWhcNMjcw - NjEzMTkzNzMzWjAcMRowGAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTBZMBMGByqG - SM49AgEGCCqGSM49AwEHA0IABOGR89IyhreSHRAi6wp9a5DBIDp4YYSdWzuEdlNx - 7pX1G4T7x68xUXJZXRUPFyT8Xzn5KwCJm8RVT+nAhrsUx6SjRTBDMA4GA1UdDwEB - /wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBQ9CUiOPhjp7KD2 - ScRDxX4IzDOrNzAKBggqhkjOPQQDAgNIADBFAiEAw6Dov0c0L++1W9VufAfSMdNR - PSDfPU0MiUiG59/VIBICIEFn/6c5eQc3hUUBL74/RmNT2b1zxBmp7RiPXJAnAAwJ - -----END CERTIFICATE----- - ca.digest: f1baffe9fe9cf8497e38a4271d67fab44423678b7e7c0f677a50f37c113d81b5 -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: ca-cert-a4f087c2ee00e6d43cfb4f6884fc1e79f7e6e08e84471 -stringData: - ca.crt: | - -----BEGIN CERTIFICATE----- - MIIBqTCCAVCgAwIBAgIQb5LqGa9gS3+Mc2ntWfSoJjAKBggqhkjOPQQDAjAcMRow - GAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTAeFw0yMjA2MTMxMzM5MTVaFw0yMzA2 - MTMxOTM5MTVaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBSb290IEludGVybWVkaWF0 - ZTEgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQImvnSuvXkGy88lvx8a7of - e0MEMRI2siVvybvWXNpeXXlixgaq7weJ7pewf3HywfO68Va6kn8ehWh7s0D7SLHM - o2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4E - FgQUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwHwYDVR0jBBgwFoAUPQlIjj4Y6eyg9knE - Q8V+CMwzqzcwCgYIKoZIzj0EAwIDRwAwRAIgNZ+JPA1OqF5DsPapAZ2YsUOgIpn3 - ZbQuYKCAV0SD4EcCIFnfA5rWrc1AgtUw5inJQqJQRNgoPuC14vACqI48BiRl - -----END CERTIFICATE----- - ca.digest: dbef7ed285fb292e24f84ffba93c48d92fa322387d85469c460c655abedd5308 -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: ca-cert-6b095c7ff377b01252a4dfec59c582fe32934fa7ed0cf -stringData: - ca.crt: | - -----BEGIN CERTIFICATE----- - MIIBujCCAV+gAwIBAgIRAMkGpj7WZf+2RFE/q7ZhejEwCgYIKoZIzj0EAwIwKjEo - MCYGA1UEAxMfRGVtbyBLb25nIFJvb3QgSW50ZXJtZWRpYXRlMSBDQTAeFw0yMjA2 - MTMxMzQwNTFaFw0yMjEyMTMwNDQwNTFaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBS - b290IEludGVybWVkaWF0ZTIgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQB - my/zhZ3F2HvHFqtQzuD3lXX8SeYakxiBQvaGkGSLKD67N3vh7iC2rTSdj/vAs8ws - Y9X+mXzS6GDKC8PbSX6xo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgw - BgEB/wIBADAdBgNVHQ4EFgQURwCm53YPStZoAMfnVyknH4IgZa4wHwYDVR0jBBgw - FoAUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwCgYIKoZIzj0EAwIDSQAwRgIhAN1pkUKc - azM4PiXOnkILB2KBDIF4XpHf+4ThDMODzXP8AiEA45KXA3qMrRPQV1oBfWZ3hLgX - gxUhveuHBXMWnzUbn6U= - -----END CERTIFICATE----- - ca.digest: 45b2b6dd9d4102955b1b1e4b540e677f140521462ed4f22fa5a713863ca84600 -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: cert-0ee0e1584c8637facac95bd5fce315367dee124c0086d41e -stringData: - tls.crt: |- - -----BEGIN CERTIFICATE----- - MIIECTCCAvGgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyAwDQYJKoZIhvcNAQEL - BQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM - CUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY - MBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u - Z2hxLmNvbTAeFw0yMTAxMTUxMTE5NDNaFw0yMjA1MzAxMTE5NDNaMIGRMQswCQYD - VQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx - EDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFzAVBgNVBAMMDnBy - b3h5LmtvbmcubGFuMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29uZ2hxLmNvbTCCASIw - DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJUbKiqoCK1BTNk/7l42n6ukyTEu - eLyB23e/90PzT/oz8wZzgwTodzbFAS2VtFr1EKqFzor0DrXp9CLnebOdiAR3I6LD - /WY/x0KW3lx3F35fGiUOSLPTH8zeiDTMx11CcKDxesA+M2/s5q0igkOQ4z4w3voz - m5a52IcQTSA8K5knNU1qUZBLpc+khxFcaheEK1jsISJJhcdizZBfGdk8S1vpyj5F - uCZ7oaRvNA6imHjSJwpgo36zd84TgrIgVj9R4QtJysWy/X+bbaKUiKBWwAtd4+DT - EP90l/ny9szu2fijk4/6k1ntXufGTyvM+J0/qJ13e99TVYOVanITnpTO+6cCAwEA - AaNWMFQwHwYDVR0jBBgwFoAUdskpf0wJRQxjtzQFZciWmUfl2bcwCQYDVR0TBAIw - ADALBgNVHQ8EBAMCBPAwGQYDVR0RBBIwEIIOcHJveHkua29uZy5sYW4wDQYJKoZI - hvcNAQELBQADggEBAJVrTWQRQzNtypa9OXFYADm8Fay1VMop3BY2kh0tfYgQEJ/4 - pJUj6CaszQZ/Aix6LaPnXFcoPCDqqv00mgju86PMamr/zA9USXk8eTmzJkp5RklS - GdqiXboqESiQVvaNz3kdW7wgNz4FwaGCzkEi/dcc2LdtzLpWizx+TlxMMqjonUUM - ovZgZo+OlhWRsDVT/qy5SFtA0vlVNtdBr2egXb1H7J8UDC+fax/iKa7+fBUHZOO9 - Fk9U8bxgfQ+jPIVVL8CfAtR68Sos7NpWH0S2emqZRnQvf0MSNdkTQKWn4qR9sckj - Ewxs5FbrMmgCOgwk1PtgRmdP3RME0HwK/B03saQ= - -----END CERTIFICATE----- - tls.key: |- - -----BEGIN PRIVATE KEY----- - MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCVGyoqqAitQUzZ - P+5eNp+rpMkxLni8gdt3v/dD80/6M/MGc4ME6Hc2xQEtlbRa9RCqhc6K9A616fQi - 53mznYgEdyOiw/1mP8dClt5cdxd+XxolDkiz0x/M3og0zMddQnCg8XrAPjNv7Oat - IoJDkOM+MN76M5uWudiHEE0gPCuZJzVNalGQS6XPpIcRXGoXhCtY7CEiSYXHYs2Q - XxnZPEtb6co+Rbgme6GkbzQOoph40icKYKN+s3fOE4KyIFY/UeELScrFsv1/m22i - lIigVsALXePg0xD/dJf58vbM7tn4o5OP+pNZ7V7nxk8rzPidP6idd3vfU1WDlWpy - E56UzvunAgMBAAECggEAcq7lHNAHdHLgT8yrY41x/AwPryNGO/9JNW7SGVKAdjoU - tyaLZHAEmXynLk+R28/YFMA8H4Yd9m9OlrYhVjRZFM4p+5vxP/7YHPB7cPUsfcda - DZxR8PX25JVYf/vtb16V0ERLnKd62qCEwC/lr2A2WHQwXJLrHeAtmZzBJYUCJ5Xj - Dv1ZhyFjknswaV0vGXe6njTI6CzMQDTGysoagpCCo7RWgzjLREg2BGWd2UQpY4AW - nYAP4QNt82UMQbgIqsEMj64mzS9Q+o1P84J1naSP5sCI22LeFRp6iezZc+D8EH/5 - RNONGSNWl3g6bsvN1VywYwjWn+waD3XAjXUu+peUgQKBgQDDu1QP28oSMKivHdfo - kQ1HrTNBRc9eWeAMZFuIbbPLN8rdEibpOm3DwTqithnahqS0NLOsBnXNtuLw1Qr/ - zmOzn0yDO5XG8dlKr9vqWeBLdcRydLJBZwqEzWf4JwwwgfK3rItRaIbnAxnGUTS5 - SrrhNfBAIGS9jx5X2kvLC7hFQQKBgQDDBIrpLTIjRDloWZcu03z9Bhb8jQCyGb5C - 4MYs+duCnQIdNq/+maPspJzbVmF4b6S1zIPweI3fMvMeqRTbuf+drpElst1buFTO - P0UMMn4V+4qGIOOkIy5JIKwR8sJD9tNDUPtxuDEotTB9IyWx6pdmCFz5v/bggDCu - reoqflL+5wKBgQCDvb+L2QS+j4/KJk0flRoaJ2K7SVCVEesyjA3r2uLMImZhvAkC - rDgbLSDZSbZHFp8fR+WzILoD11gSf2Ki4PjMeqkWH3HlcP0vPwTHTO0h/UdXPmKI - kOFMl7CmHyoeMCj9JZ60EaXTMYwUpq3VFY6JbTOjBeqoh/8FZMHlDaNewQKBgCHg - ECEg8KyflTlDFrfTlMp+3E9STuShBCOp18LIRBEUJOHeNgQLvCXHElgnURcSjZHm - zKRgzIQQ3Zpd1Hm2fWhuglgCEeF0y4ZoBx5vRueaoh1aaTCBy/B39GvJt2UG4vu2 - fXbrf96KWrnh+RJGpbXbjgr0BXZJzisJmrt25gPRAoGBAI3c+INpQXwrE+LBzCPu - LwIVvkm5NpeIlKQtDNrqG1QvUhqyZ2/Xitc4FyiccW7WHxkGKGZyj7GbmpqEOnyY - iVku0LSftZgycet2uMdp0HaVAgi5S6aVf5yN0U/8R5ToxcbuEfqwrBIyRgse8lx3 - NNSvLxPAempmiFPSk9AtobYV - -----END PRIVATE KEY----- -type: kubernetes.io/tls ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: cert-b12464ec431576239dd9cc2545d528f6cbdbd988cf076323 -stringData: - tls.crt: |- - -----BEGIN CERTIFICATE----- - MIIFeDCCBGCgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyQwDQYJKoZIhvcNAQEL - BQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM - CUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY - MBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u - Z2hxLmNvbTAeFw0yMTAxMjAxNTA0NDVaFw0yMjAxMjAxNTA0NDVaMIGQMQswCQYD - VQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx - EDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFjAUBgNVBAMMDW10 - bHMtY29uc3VtZXIxHTAbBgkqhkiG9w0BCQEWDnN0dUBrb25naHEuY29tMIICIjAN - BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1/+83/YNiEVKYvcuVwYGve6afsg1 - BYCn1+E9Uwgh0uwAenT/DKB8NhqoVxc7cZ2HaTI146IGmFICmctlTWvLPLglHmTo - byOUV6tIJAjvzyEOpC458hLGgbv8mhGXJWPxBVu7Wy6Hapz2bk0cEscfL7PHKaRu - 3D6r8/zbhhWAqe4EIt+NVYT6baaYBs7bPZQXs/sluKI+DNYuDeaAmoSuCc4ein6z - 0xDqCSMmPebzjns03ttB29vWL3eYY9dvgoCd+CPhXT/C4CHtvKbH+hOQYDtVF6MO - 1mmABAQTQWMR/00+QI0xtvuXtEPurla5dA0TN6ddCTOOcILKx62z5oc3Kqr+nHHa - 71zNzARUVaZ2vy1pRVr0DZgB7KqcFXhy/oy8IpmxUR1ASBDZl6B6RKrdQwvgLgmn - 3M/roNLAU+3nz4itpt/zf+X0suwdthrflic1R68z1SlYbyoGARWkZ/pOl6kLNVK2 - OsqQuICaajnW7t1oDd7z1+3hm+uoryDwvG6f3T9ZvWjKXYcKg7b+BjbFdahbDywD - PgnhSz9AaoVWhR+GHIPrjRClMpEkra/yGJFvH3UpXhgg9d0DrLZE51Z75a9SvnAj - vdLuNhx4bJbwLBgNGsJMkupzBrw4iCfbKFcBbP8o0Xjtarj7T/mkWuQ1GjWqfyrD - 55NecBPNw5C9BR0CAwEAAaOBxTCBwjAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQE - AwIFoDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgQ2xpZW50IENl - cnRpZmljYXRlMB0GA1UdDgQWBBSV3F+eicU8SVT4LcDJ6eMzP0todzAfBgNVHSME - GDAWgBR2ySl/TAlFDGO3NAVlyJaZR+XZtzAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0l - BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4IBAQB5L0OZ - WELG9Pw6Ol1BsZYgpLR4PGNBB9dKm/9dd+q+ohZVFCfXcjZ3YOU1vh/HHQrALRNY - I58JxcVCOx/qIW2uA0iSCqIT0sNb9cJLxfZf7X+BzPPPnu0ugUJp7GzLNnHitrLC - Xb1nmmefwgraNzp+a5IrR8RcQG1mYDuS+2HK/rybo22XcCxhob8OiDEn8+ytkKyQ - Ipmrf9D+/68/ih6az0w1aakASMmFe8z/p6VgVQkCySCWWFG525BRdGmSImqVZ4xa - aQFN3L+oN+JJcCFTthLOAYo32JH+xLMz7PokzSL84g3b68h59hXDoMSwB10GthL5 - T8tqV6i5miKWwvfZ - -----END CERTIFICATE----- - tls.key: |- - -----BEGIN RSA PRIVATE KEY----- - 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 - -----END RSA PRIVATE KEY----- -type: kubernetes.io/tls ---- -apiVersion: configuration.konghq.com/v1 -consumerGroups: -- example-consumer-group -credentials: -- key-auth-example-user -- jwt-auth-example-user -- basic-auth-example-user -- acl-group-example-user -- mtls-auth-example-user -custom_id: "1234567890" -kind: KongConsumer -metadata: - annotations: - konghq.com/plugins: example-user-rate-limiting-advanced - kubernetes.io/ingress.class: kong - name: example-user -username: example-user ---- -apiVersion: configuration.konghq.com/v1beta1 -kind: KongConsumerGroup -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-consumer-group ---- diff --git a/kong2kic/testdata/kicv3_ingress/output-expected.json b/kong2kic/testdata/kicv3_ingress/output-expected.json deleted file mode 100644 index 2a444ceff..000000000 --- a/kong2kic/testdata/kicv3_ingress/output-expected.json +++ /dev/null @@ -1,753 +0,0 @@ -{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_client_headers": false, - "identifier": "consumer", - "limit": [ - 5 - ], - "namespace": "example_namespace", - "strategy": "local", - "sync_rate": -1, - "window_size": [ - 30 - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service-rate-limiting-advanced" - }, - "plugin": "rate-limiting-advanced" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "aws_key": "my_key", - "aws_region": "us-west-2", - "aws_secret": "my_secret", - "function_name": "my_function" - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long9344b5559f" - }, - "plugin": "aws-lambda" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "credentials": true, - "exposed_headers": [ - "X-My-Header" - ], - "headers": [ - "Authorization" - ], - "max_age": 3600, - "methods": [ - "GET", - "POST" - ], - "origins": [ - "example.com" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longfdeaa51f90" - }, - "plugin": "cors" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "path": "/var/log/kong/kong.log", - "reopen": true - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long3b4b1fae8e" - }, - "plugin": "file-log" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "content_type": "application/json", - "http_endpoint": "http://example.com/logs", - "keepalive": 60000, - "method": "POST", - "queue_size": 1000, - "retry_count": 10, - "timeout": 10000 - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long59030a424c" - }, - "plugin": "http-log" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "allow": [ - "192.168.0.1/24" - ], - "deny": [ - "192.168.0.2/32" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longb44edd01cf" - }, - "plugin": "ip-restriction" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_client_headers": false, - "identifier": "consumer", - "limit": [ - 5 - ], - "namespace": "example_namespace", - "strategy": "local", - "sync_rate": -1, - "window_size": [ - 30 - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longef35b834c6" - }, - "plugin": "rate-limiting-advanced" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "message": "Forbidden", - "status_code": 403 - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longb2c08ebc54" - }, - "plugin": "request-termination" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "limits": { - "limit_name": { - "minute": 10 - } - }, - "policy": "local" - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longc400f1ab11" - }, - "plugin": "response-ratelimiting" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "host": "example.com", - "port": 1234 - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long47f9f5054d" - }, - "plugin": "tcp-log" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_credentials": false - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long26f9714514" - }, - "plugin": "basic-auth" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "anonymous": null, - "claims_to_verify": [ - "exp", - "nbf" - ], - "header_names": [ - "Authorization" - ], - "key_claim_name": "kid", - "maximum_expiration": 3600, - "run_on_preflight": true, - "secret_is_base64": false, - "uri_param_names": [ - "token" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long0239c8f63e" - }, - "plugin": "jwt" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_credentials": false, - "key_in_body": false, - "key_names": [ - "apikey" - ], - "run_on_preflight": true - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long5494737f3e" - }, - "plugin": "key-auth" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "ca_certificates": [ - "cce8c384-721f-4f58-85dd-50834e3e733a" - ], - "revocation_check_mode": "SKIP", - "skip_consumer_lookup": false - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-long89ae2d2b5d" - }, - "plugin": "mtls-auth" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "allow": [ - "admin" - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-service--route-thisisaveryvery-longb2440ac898" - }, - "plugin": "acl" -}{ - "apiVersion": "configuration.konghq.com/v1", - "config": { - "hide_client_headers": false, - "identifier": "consumer", - "limit": [ - 5 - ], - "namespace": "example_namespace", - "strategy": "local", - "sync_rate": -1, - "window_size": [ - 30 - ] - }, - "kind": "KongPlugin", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-user-rate-limiting-advanced" - }, - "plugin": "rate-limiting-advanced" -}{ - "apiVersion": "networking.k8s.io/v1", - "kind": "Ingress", - "metadata": { - "annotations": { - "konghq.com/headers.x-another-header": "first-header-value,second-header-value", - "konghq.com/headers.x-my-header": "~*foos?bar$", - "konghq.com/https-redirect-status-code": "302", - "konghq.com/methods": "GET,POST", - "konghq.com/plugins": "example-service--route-thisisaveryvery-long9344b5559f,example-service--route-thisisaveryvery-longfdeaa51f90,example-service--route-thisisaveryvery-long3b4b1fae8e,example-service--route-thisisaveryvery-long59030a424c,example-service--route-thisisaveryvery-longb44edd01cf,example-service--route-thisisaveryvery-longef35b834c6,example-service--route-thisisaveryvery-longb2c08ebc54,example-service--route-thisisaveryvery-longc400f1ab11,example-service--route-thisisaveryvery-long47f9f5054d,example-service--route-thisisaveryvery-long26f9714514,example-service--route-thisisaveryvery-long0239c8f63e,example-service--route-thisisaveryvery-long5494737f3e,example-service--route-thisisaveryvery-long89ae2d2b5d,example-service--route-thisisaveryvery-longb2440ac898", - "konghq.com/preserve-host": "true", - "konghq.com/protocols": "http,https", - "konghq.com/regex-priority": "1", - "konghq.com/snis": "example.com", - "konghq.com/strip-path": "false" - }, - "name": "example-service--route-thisisaveryvery-long2093a020ca" - }, - "spec": { - "ingressClassName": "kong", - "rules": [ - { - "host": "example.com", - "http": { - "paths": [ - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/~/v1/example/?$", - "pathType": "ImplementationSpecific" - }, - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/v1/another-example", - "pathType": "ImplementationSpecific" - }, - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/v1/yet-another-example", - "pathType": "ImplementationSpecific" - } - ] - } - }, - { - "host": "another-example.com", - "http": { - "paths": [ - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/~/v1/example/?$", - "pathType": "ImplementationSpecific" - }, - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/v1/another-example", - "pathType": "ImplementationSpecific" - }, - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/v1/yet-another-example", - "pathType": "ImplementationSpecific" - } - ] - } - }, - { - "host": "yet-another-example.com", - "http": { - "paths": [ - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/~/v1/example/?$", - "pathType": "ImplementationSpecific" - }, - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/v1/another-example", - "pathType": "ImplementationSpecific" - }, - { - "backend": { - "service": { - "name": "example-service", - "port": { - "number": 80 - } - } - }, - "path": "/v1/yet-another-example", - "pathType": "ImplementationSpecific" - } - ] - } - } - ] - } -}{ - "apiVersion": "configuration.konghq.com/v1beta1", - "kind": "KongUpstreamPolicy", - "metadata": { - "name": "example-service-upstream" - }, - "spec": { - "algorithm": "round-robin", - "healthchecks": { - "active": { - "concurrency": 10, - "headers": { - "x-another-header": [ - "bla" - ], - "x-my-header": [ - "foo", - "bar" - ] - }, - "healthy": { - "httpStatuses": [ - 200, - 302 - ], - "interval": 0, - "successes": 0 - }, - "httpPath": "/", - "httpsSni": "example.com", - "httpsVerifyCertificate": true, - "timeout": 1, - "type": "http", - "unhealthy": { - "httpFailures": 0, - "httpStatuses": [ - 429, - 404, - 500, - 501, - 502, - 503, - 504, - 505 - ], - "interval": 0, - "tcpFailures": 0, - "timeouts": 0 - } - }, - "passive": { - "healthy": { - "httpStatuses": [ - 200, - 201, - 202, - 203, - 204, - 205, - 206, - 207, - 208, - 226, - 300, - 301, - 302, - 303, - 304, - 305, - 306, - 307, - 308 - ], - "successes": 0 - }, - "type": "http", - "unhealthy": { - "httpFailures": 0, - "httpStatuses": [ - 429, - 500, - 503 - ], - "tcpFailures": 0, - "timeouts": 0 - } - }, - "threshold": 0 - }, - "slots": 10000 - } -}{ - "apiVersion": "v1", - "kind": "Service", - "metadata": { - "annotations": { - "konghq.com/connect-timeout": "5000", - "konghq.com/path": "/v1", - "konghq.com/plugins": "example-service-rate-limiting-advanced", - "konghq.com/protocol": "http", - "konghq.com/read-timeout": "60000", - "konghq.com/retries": "5", - "konghq.com/upstream-policy": "example-service-upstream", - "konghq.com/write-timeout": "60000" - }, - "name": "example-service" - }, - "spec": { - "ports": [ - { - "port": 80, - "protocol": "TCP", - "targetPort": 80 - } - ], - "selector": { - "app": "example-service" - } - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "labels": { - "konghq.com/credential": "key-auth" - }, - "name": "key-auth-example-user" - }, - "stringData": { - "key": "my_api_key" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "labels": { - "konghq.com/credential": "jwt" - }, - "name": "jwt-auth-example-user" - }, - "stringData": { - "algorithm": "HS256", - "key": "my_jwt_secret", - "rsa_public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxXzYS5yESbekTF3xLiQX\nZZZfXt0S/nzFp3f2Oux3W7/ydvZ8XSd8+s+wm5oqEcSV9n+5n3ENZbt1A/wgnGI3\noWrv0yRB9HugzTIGPpI1AQv9Z4p8E44RrB74/uTxYwb9+4yvpuz/fzTt3Gz+Kzc4\n4fGGq8VpGMFj6AE65ZcOAHHUJe4VuoreBXLYDJcHl2WPIdNKDGscFjElDneLRhWQ\nDfxekDJIQMWCjyBEXacfP6cc9U8Qld6TuVcwi1P2xb8tBDD4MIFL/psfzUhfv1Lw\nO/XZEffJxCqkQn7dsCYy3wpaTjb6XmJ5j0Dbml4f0Bv40Y1mjlAf7C662Mbuguf6\newIDAQAB\n-----END PUBLIC KEY-----", - "secret": "my_secret_key" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "labels": { - "konghq.com/credential": "basic-auth" - }, - "name": "basic-auth-example-user" - }, - "stringData": { - "password": "my_basic_password", - "username": "my_basic_user" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "labels": { - "konghq.com/credential": "acl" - }, - "name": "acl-group-example-user" - }, - "stringData": { - "group": "acl_group" - } -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "labels": { - "konghq.com/credential": "mtls-auth" - }, - "name": "mtls-auth-example-user" - }, - "stringData": { - "id": "cce8c384-721f-4f58-85dd-50834e3e733a", - "subject_name": "example-user@example.com" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "ca-cert-a672ab52d2341203bd70116b456413d7ac3ffc162abbf" - }, - "stringData": { - "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIBfDCCASKgAwIBAgIRAJqcZC1VSvSQLMN1+7yAeswwCgYIKoZIzj0EAwIwHDEa\nMBgGA1UEAxMRRGVtbyBLb25nIFJvb3QgQ0EwHhcNMjIwNjEzMTMzNzMzWhcNMjcw\nNjEzMTkzNzMzWjAcMRowGAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTBZMBMGByqG\nSM49AgEGCCqGSM49AwEHA0IABOGR89IyhreSHRAi6wp9a5DBIDp4YYSdWzuEdlNx\n7pX1G4T7x68xUXJZXRUPFyT8Xzn5KwCJm8RVT+nAhrsUx6SjRTBDMA4GA1UdDwEB\n/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBQ9CUiOPhjp7KD2\nScRDxX4IzDOrNzAKBggqhkjOPQQDAgNIADBFAiEAw6Dov0c0L++1W9VufAfSMdNR\nPSDfPU0MiUiG59/VIBICIEFn/6c5eQc3hUUBL74/RmNT2b1zxBmp7RiPXJAnAAwJ\n-----END CERTIFICATE-----\n", - "ca.digest": "f1baffe9fe9cf8497e38a4271d67fab44423678b7e7c0f677a50f37c113d81b5" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "ca-cert-a4f087c2ee00e6d43cfb4f6884fc1e79f7e6e08e84471" - }, - "stringData": { - "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIBqTCCAVCgAwIBAgIQb5LqGa9gS3+Mc2ntWfSoJjAKBggqhkjOPQQDAjAcMRow\nGAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTAeFw0yMjA2MTMxMzM5MTVaFw0yMzA2\nMTMxOTM5MTVaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBSb290IEludGVybWVkaWF0\nZTEgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQImvnSuvXkGy88lvx8a7of\ne0MEMRI2siVvybvWXNpeXXlixgaq7weJ7pewf3HywfO68Va6kn8ehWh7s0D7SLHM\no2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4E\nFgQUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwHwYDVR0jBBgwFoAUPQlIjj4Y6eyg9knE\nQ8V+CMwzqzcwCgYIKoZIzj0EAwIDRwAwRAIgNZ+JPA1OqF5DsPapAZ2YsUOgIpn3\nZbQuYKCAV0SD4EcCIFnfA5rWrc1AgtUw5inJQqJQRNgoPuC14vACqI48BiRl\n-----END CERTIFICATE-----\n", - "ca.digest": "dbef7ed285fb292e24f84ffba93c48d92fa322387d85469c460c655abedd5308" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "ca-cert-6b095c7ff377b01252a4dfec59c582fe32934fa7ed0cf" - }, - "stringData": { - "ca.crt": "-----BEGIN CERTIFICATE-----\nMIIBujCCAV+gAwIBAgIRAMkGpj7WZf+2RFE/q7ZhejEwCgYIKoZIzj0EAwIwKjEo\nMCYGA1UEAxMfRGVtbyBLb25nIFJvb3QgSW50ZXJtZWRpYXRlMSBDQTAeFw0yMjA2\nMTMxMzQwNTFaFw0yMjEyMTMwNDQwNTFaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBS\nb290IEludGVybWVkaWF0ZTIgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQB\nmy/zhZ3F2HvHFqtQzuD3lXX8SeYakxiBQvaGkGSLKD67N3vh7iC2rTSdj/vAs8ws\nY9X+mXzS6GDKC8PbSX6xo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgw\nBgEB/wIBADAdBgNVHQ4EFgQURwCm53YPStZoAMfnVyknH4IgZa4wHwYDVR0jBBgw\nFoAUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwCgYIKoZIzj0EAwIDSQAwRgIhAN1pkUKc\nazM4PiXOnkILB2KBDIF4XpHf+4ThDMODzXP8AiEA45KXA3qMrRPQV1oBfWZ3hLgX\ngxUhveuHBXMWnzUbn6U=\n-----END CERTIFICATE-----\n", - "ca.digest": "45b2b6dd9d4102955b1b1e4b540e677f140521462ed4f22fa5a713863ca84600" - }, - "type": "Opaque" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "cert-0ee0e1584c8637facac95bd5fce315367dee124c0086d41e" - }, - "stringData": { - "tls.crt": "-----BEGIN CERTIFICATE-----\nMIIECTCCAvGgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyAwDQYJKoZIhvcNAQEL\nBQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM\nCUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY\nMBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u\nZ2hxLmNvbTAeFw0yMTAxMTUxMTE5NDNaFw0yMjA1MzAxMTE5NDNaMIGRMQswCQYD\nVQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx\nEDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFzAVBgNVBAMMDnBy\nb3h5LmtvbmcubGFuMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29uZ2hxLmNvbTCCASIw\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJUbKiqoCK1BTNk/7l42n6ukyTEu\neLyB23e/90PzT/oz8wZzgwTodzbFAS2VtFr1EKqFzor0DrXp9CLnebOdiAR3I6LD\n/WY/x0KW3lx3F35fGiUOSLPTH8zeiDTMx11CcKDxesA+M2/s5q0igkOQ4z4w3voz\nm5a52IcQTSA8K5knNU1qUZBLpc+khxFcaheEK1jsISJJhcdizZBfGdk8S1vpyj5F\nuCZ7oaRvNA6imHjSJwpgo36zd84TgrIgVj9R4QtJysWy/X+bbaKUiKBWwAtd4+DT\nEP90l/ny9szu2fijk4/6k1ntXufGTyvM+J0/qJ13e99TVYOVanITnpTO+6cCAwEA\nAaNWMFQwHwYDVR0jBBgwFoAUdskpf0wJRQxjtzQFZciWmUfl2bcwCQYDVR0TBAIw\nADALBgNVHQ8EBAMCBPAwGQYDVR0RBBIwEIIOcHJveHkua29uZy5sYW4wDQYJKoZI\nhvcNAQELBQADggEBAJVrTWQRQzNtypa9OXFYADm8Fay1VMop3BY2kh0tfYgQEJ/4\npJUj6CaszQZ/Aix6LaPnXFcoPCDqqv00mgju86PMamr/zA9USXk8eTmzJkp5RklS\nGdqiXboqESiQVvaNz3kdW7wgNz4FwaGCzkEi/dcc2LdtzLpWizx+TlxMMqjonUUM\novZgZo+OlhWRsDVT/qy5SFtA0vlVNtdBr2egXb1H7J8UDC+fax/iKa7+fBUHZOO9\nFk9U8bxgfQ+jPIVVL8CfAtR68Sos7NpWH0S2emqZRnQvf0MSNdkTQKWn4qR9sckj\nEwxs5FbrMmgCOgwk1PtgRmdP3RME0HwK/B03saQ=\n-----END CERTIFICATE-----", - "tls.key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCVGyoqqAitQUzZ\nP+5eNp+rpMkxLni8gdt3v/dD80/6M/MGc4ME6Hc2xQEtlbRa9RCqhc6K9A616fQi\n53mznYgEdyOiw/1mP8dClt5cdxd+XxolDkiz0x/M3og0zMddQnCg8XrAPjNv7Oat\nIoJDkOM+MN76M5uWudiHEE0gPCuZJzVNalGQS6XPpIcRXGoXhCtY7CEiSYXHYs2Q\nXxnZPEtb6co+Rbgme6GkbzQOoph40icKYKN+s3fOE4KyIFY/UeELScrFsv1/m22i\nlIigVsALXePg0xD/dJf58vbM7tn4o5OP+pNZ7V7nxk8rzPidP6idd3vfU1WDlWpy\nE56UzvunAgMBAAECggEAcq7lHNAHdHLgT8yrY41x/AwPryNGO/9JNW7SGVKAdjoU\ntyaLZHAEmXynLk+R28/YFMA8H4Yd9m9OlrYhVjRZFM4p+5vxP/7YHPB7cPUsfcda\nDZxR8PX25JVYf/vtb16V0ERLnKd62qCEwC/lr2A2WHQwXJLrHeAtmZzBJYUCJ5Xj\nDv1ZhyFjknswaV0vGXe6njTI6CzMQDTGysoagpCCo7RWgzjLREg2BGWd2UQpY4AW\nnYAP4QNt82UMQbgIqsEMj64mzS9Q+o1P84J1naSP5sCI22LeFRp6iezZc+D8EH/5\nRNONGSNWl3g6bsvN1VywYwjWn+waD3XAjXUu+peUgQKBgQDDu1QP28oSMKivHdfo\nkQ1HrTNBRc9eWeAMZFuIbbPLN8rdEibpOm3DwTqithnahqS0NLOsBnXNtuLw1Qr/\nzmOzn0yDO5XG8dlKr9vqWeBLdcRydLJBZwqEzWf4JwwwgfK3rItRaIbnAxnGUTS5\nSrrhNfBAIGS9jx5X2kvLC7hFQQKBgQDDBIrpLTIjRDloWZcu03z9Bhb8jQCyGb5C\n4MYs+duCnQIdNq/+maPspJzbVmF4b6S1zIPweI3fMvMeqRTbuf+drpElst1buFTO\nP0UMMn4V+4qGIOOkIy5JIKwR8sJD9tNDUPtxuDEotTB9IyWx6pdmCFz5v/bggDCu\nreoqflL+5wKBgQCDvb+L2QS+j4/KJk0flRoaJ2K7SVCVEesyjA3r2uLMImZhvAkC\nrDgbLSDZSbZHFp8fR+WzILoD11gSf2Ki4PjMeqkWH3HlcP0vPwTHTO0h/UdXPmKI\nkOFMl7CmHyoeMCj9JZ60EaXTMYwUpq3VFY6JbTOjBeqoh/8FZMHlDaNewQKBgCHg\nECEg8KyflTlDFrfTlMp+3E9STuShBCOp18LIRBEUJOHeNgQLvCXHElgnURcSjZHm\nzKRgzIQQ3Zpd1Hm2fWhuglgCEeF0y4ZoBx5vRueaoh1aaTCBy/B39GvJt2UG4vu2\nfXbrf96KWrnh+RJGpbXbjgr0BXZJzisJmrt25gPRAoGBAI3c+INpQXwrE+LBzCPu\nLwIVvkm5NpeIlKQtDNrqG1QvUhqyZ2/Xitc4FyiccW7WHxkGKGZyj7GbmpqEOnyY\niVku0LSftZgycet2uMdp0HaVAgi5S6aVf5yN0U/8R5ToxcbuEfqwrBIyRgse8lx3\nNNSvLxPAempmiFPSk9AtobYV\n-----END PRIVATE KEY-----" - }, - "type": "kubernetes.io/tls" -}{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "cert-b12464ec431576239dd9cc2545d528f6cbdbd988cf076323" - }, - "stringData": { - "tls.crt": "-----BEGIN CERTIFICATE-----\nMIIFeDCCBGCgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyQwDQYJKoZIhvcNAQEL\nBQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM\nCUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY\nMBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u\nZ2hxLmNvbTAeFw0yMTAxMjAxNTA0NDVaFw0yMjAxMjAxNTA0NDVaMIGQMQswCQYD\nVQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx\nEDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFjAUBgNVBAMMDW10\nbHMtY29uc3VtZXIxHTAbBgkqhkiG9w0BCQEWDnN0dUBrb25naHEuY29tMIICIjAN\nBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1/+83/YNiEVKYvcuVwYGve6afsg1\nBYCn1+E9Uwgh0uwAenT/DKB8NhqoVxc7cZ2HaTI146IGmFICmctlTWvLPLglHmTo\nbyOUV6tIJAjvzyEOpC458hLGgbv8mhGXJWPxBVu7Wy6Hapz2bk0cEscfL7PHKaRu\n3D6r8/zbhhWAqe4EIt+NVYT6baaYBs7bPZQXs/sluKI+DNYuDeaAmoSuCc4ein6z\n0xDqCSMmPebzjns03ttB29vWL3eYY9dvgoCd+CPhXT/C4CHtvKbH+hOQYDtVF6MO\n1mmABAQTQWMR/00+QI0xtvuXtEPurla5dA0TN6ddCTOOcILKx62z5oc3Kqr+nHHa\n71zNzARUVaZ2vy1pRVr0DZgB7KqcFXhy/oy8IpmxUR1ASBDZl6B6RKrdQwvgLgmn\n3M/roNLAU+3nz4itpt/zf+X0suwdthrflic1R68z1SlYbyoGARWkZ/pOl6kLNVK2\nOsqQuICaajnW7t1oDd7z1+3hm+uoryDwvG6f3T9ZvWjKXYcKg7b+BjbFdahbDywD\nPgnhSz9AaoVWhR+GHIPrjRClMpEkra/yGJFvH3UpXhgg9d0DrLZE51Z75a9SvnAj\nvdLuNhx4bJbwLBgNGsJMkupzBrw4iCfbKFcBbP8o0Xjtarj7T/mkWuQ1GjWqfyrD\n55NecBPNw5C9BR0CAwEAAaOBxTCBwjAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQE\nAwIFoDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgQ2xpZW50IENl\ncnRpZmljYXRlMB0GA1UdDgQWBBSV3F+eicU8SVT4LcDJ6eMzP0todzAfBgNVHSME\nGDAWgBR2ySl/TAlFDGO3NAVlyJaZR+XZtzAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0l\nBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4IBAQB5L0OZ\nWELG9Pw6Ol1BsZYgpLR4PGNBB9dKm/9dd+q+ohZVFCfXcjZ3YOU1vh/HHQrALRNY\nI58JxcVCOx/qIW2uA0iSCqIT0sNb9cJLxfZf7X+BzPPPnu0ugUJp7GzLNnHitrLC\nXb1nmmefwgraNzp+a5IrR8RcQG1mYDuS+2HK/rybo22XcCxhob8OiDEn8+ytkKyQ\nIpmrf9D+/68/ih6az0w1aakASMmFe8z/p6VgVQkCySCWWFG525BRdGmSImqVZ4xa\naQFN3L+oN+JJcCFTthLOAYo32JH+xLMz7PokzSL84g3b68h59hXDoMSwB10GthL5\nT8tqV6i5miKWwvfZ\n-----END CERTIFICATE-----", - "tls.key": "-----BEGIN RSA PRIVATE KEY-----\n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\n-----END RSA PRIVATE KEY-----" - }, - "type": "kubernetes.io/tls" -}{ - "apiVersion": "configuration.konghq.com/v1", - "consumerGroups": [ - "example-consumer-group" - ], - "credentials": [ - "key-auth-example-user", - "jwt-auth-example-user", - "basic-auth-example-user", - "acl-group-example-user", - "mtls-auth-example-user" - ], - "custom_id": "1234567890", - "kind": "KongConsumer", - "metadata": { - "annotations": { - "konghq.com/plugins": "example-user-rate-limiting-advanced", - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-user" - }, - "username": "example-user" -}{ - "apiVersion": "configuration.konghq.com/v1beta1", - "kind": "KongConsumerGroup", - "metadata": { - "annotations": { - "kubernetes.io/ingress.class": "kong" - }, - "name": "example-consumer-group" - } -} \ No newline at end of file diff --git a/kong2kic/testdata/kicv3_ingress/output-expected.yaml b/kong2kic/testdata/kicv3_ingress/output-expected.yaml deleted file mode 100644 index 19dcabdb3..000000000 --- a/kong2kic/testdata/kicv3_ingress/output-expected.yaml +++ /dev/null @@ -1,736 +0,0 @@ -apiVersion: configuration.konghq.com/v1 -config: - hide_client_headers: false - identifier: consumer - limit: - - 5 - namespace: example_namespace - strategy: local - sync_rate: -1 - window_size: - - 30 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service-rate-limiting-advanced -plugin: rate-limiting-advanced ---- -apiVersion: configuration.konghq.com/v1 -config: - aws_key: my_key - aws_region: us-west-2 - aws_secret: my_secret - function_name: my_function -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long9344b5559f -plugin: aws-lambda ---- -apiVersion: configuration.konghq.com/v1 -config: - credentials: true - exposed_headers: - - X-My-Header - headers: - - Authorization - max_age: 3600 - methods: - - GET - - POST - origins: - - example.com -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longfdeaa51f90 -plugin: cors ---- -apiVersion: configuration.konghq.com/v1 -config: - path: /var/log/kong/kong.log - reopen: true -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long3b4b1fae8e -plugin: file-log ---- -apiVersion: configuration.konghq.com/v1 -config: - content_type: application/json - http_endpoint: http://example.com/logs - keepalive: 60000 - method: POST - queue_size: 1000 - retry_count: 10 - timeout: 10000 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long59030a424c -plugin: http-log ---- -apiVersion: configuration.konghq.com/v1 -config: - allow: - - 192.168.0.1/24 - deny: - - 192.168.0.2/32 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longb44edd01cf -plugin: ip-restriction ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_client_headers: false - identifier: consumer - limit: - - 5 - namespace: example_namespace - strategy: local - sync_rate: -1 - window_size: - - 30 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longef35b834c6 -plugin: rate-limiting-advanced ---- -apiVersion: configuration.konghq.com/v1 -config: - message: Forbidden - status_code: 403 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longb2c08ebc54 -plugin: request-termination ---- -apiVersion: configuration.konghq.com/v1 -config: - limits: - limit_name: - minute: 10 - policy: local -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longc400f1ab11 -plugin: response-ratelimiting ---- -apiVersion: configuration.konghq.com/v1 -config: - host: example.com - port: 1234 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long47f9f5054d -plugin: tcp-log ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_credentials: false -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long26f9714514 -plugin: basic-auth ---- -apiVersion: configuration.konghq.com/v1 -config: - anonymous: null - claims_to_verify: - - exp - - nbf - header_names: - - Authorization - key_claim_name: kid - maximum_expiration: 3600 - run_on_preflight: true - secret_is_base64: false - uri_param_names: - - token -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long0239c8f63e -plugin: jwt ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_credentials: false - key_in_body: false - key_names: - - apikey - run_on_preflight: true -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long5494737f3e -plugin: key-auth ---- -apiVersion: configuration.konghq.com/v1 -config: - ca_certificates: - - cce8c384-721f-4f58-85dd-50834e3e733a - revocation_check_mode: SKIP - skip_consumer_lookup: false -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-long89ae2d2b5d -plugin: mtls-auth ---- -apiVersion: configuration.konghq.com/v1 -config: - allow: - - admin -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-service--route-thisisaveryvery-longb2440ac898 -plugin: acl ---- -apiVersion: configuration.konghq.com/v1 -config: - hide_client_headers: false - identifier: consumer - limit: - - 5 - namespace: example_namespace - strategy: local - sync_rate: -1 - window_size: - - 30 -kind: KongPlugin -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-user-rate-limiting-advanced -plugin: rate-limiting-advanced ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - konghq.com/headers.x-another-header: first-header-value,second-header-value - konghq.com/headers.x-my-header: ~*foos?bar$ - konghq.com/https-redirect-status-code: "302" - konghq.com/methods: GET,POST - konghq.com/plugins: example-service--route-thisisaveryvery-long9344b5559f,example-service--route-thisisaveryvery-longfdeaa51f90,example-service--route-thisisaveryvery-long3b4b1fae8e,example-service--route-thisisaveryvery-long59030a424c,example-service--route-thisisaveryvery-longb44edd01cf,example-service--route-thisisaveryvery-longef35b834c6,example-service--route-thisisaveryvery-longb2c08ebc54,example-service--route-thisisaveryvery-longc400f1ab11,example-service--route-thisisaveryvery-long47f9f5054d,example-service--route-thisisaveryvery-long26f9714514,example-service--route-thisisaveryvery-long0239c8f63e,example-service--route-thisisaveryvery-long5494737f3e,example-service--route-thisisaveryvery-long89ae2d2b5d,example-service--route-thisisaveryvery-longb2440ac898 - konghq.com/preserve-host: "true" - konghq.com/protocols: http,https - konghq.com/regex-priority: "1" - konghq.com/snis: example.com - konghq.com/strip-path: "false" - name: example-service--route-thisisaveryvery-long2093a020ca -spec: - ingressClassName: kong - rules: - - host: example.com - http: - paths: - - backend: - service: - name: example-service - port: - number: 80 - path: /~/v1/example/?$ - pathType: ImplementationSpecific - - backend: - service: - name: example-service - port: - number: 80 - path: /v1/another-example - pathType: ImplementationSpecific - - backend: - service: - name: example-service - port: - number: 80 - path: /v1/yet-another-example - pathType: ImplementationSpecific - - host: another-example.com - http: - paths: - - backend: - service: - name: example-service - port: - number: 80 - path: /~/v1/example/?$ - pathType: ImplementationSpecific - - backend: - service: - name: example-service - port: - number: 80 - path: /v1/another-example - pathType: ImplementationSpecific - - backend: - service: - name: example-service - port: - number: 80 - path: /v1/yet-another-example - pathType: ImplementationSpecific - - host: yet-another-example.com - http: - paths: - - backend: - service: - name: example-service - port: - number: 80 - path: /~/v1/example/?$ - pathType: ImplementationSpecific - - backend: - service: - name: example-service - port: - number: 80 - path: /v1/another-example - pathType: ImplementationSpecific - - backend: - service: - name: example-service - port: - number: 80 - path: /v1/yet-another-example - pathType: ImplementationSpecific ---- -apiVersion: configuration.konghq.com/v1beta1 -kind: KongUpstreamPolicy -metadata: - name: example-service-upstream -spec: - algorithm: round-robin - healthchecks: - active: - concurrency: 10 - headers: - x-another-header: - - bla - x-my-header: - - foo - - bar - healthy: - httpStatuses: - - 200 - - 302 - interval: 0 - successes: 0 - httpPath: / - httpsSni: example.com - httpsVerifyCertificate: true - timeout: 1 - type: http - unhealthy: - httpFailures: 0 - httpStatuses: - - 429 - - 404 - - 500 - - 501 - - 502 - - 503 - - 504 - - 505 - interval: 0 - tcpFailures: 0 - timeouts: 0 - passive: - healthy: - httpStatuses: - - 200 - - 201 - - 202 - - 203 - - 204 - - 205 - - 206 - - 207 - - 208 - - 226 - - 300 - - 301 - - 302 - - 303 - - 304 - - 305 - - 306 - - 307 - - 308 - successes: 0 - type: http - unhealthy: - httpFailures: 0 - httpStatuses: - - 429 - - 500 - - 503 - tcpFailures: 0 - timeouts: 0 - threshold: 0 - slots: 10000 ---- -apiVersion: v1 -kind: Service -metadata: - annotations: - konghq.com/connect-timeout: "5000" - konghq.com/path: /v1 - konghq.com/plugins: example-service-rate-limiting-advanced - konghq.com/protocol: http - konghq.com/read-timeout: "60000" - konghq.com/retries: "5" - konghq.com/upstream-policy: example-service-upstream - konghq.com/write-timeout: "60000" - name: example-service -spec: - ports: - - port: 80 - protocol: TCP - targetPort: 80 - selector: - app: example-service ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - labels: - konghq.com/credential: key-auth - name: key-auth-example-user -stringData: - key: my_api_key ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - labels: - konghq.com/credential: jwt - name: jwt-auth-example-user -stringData: - algorithm: HS256 - key: my_jwt_secret - rsa_public_key: |- - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxXzYS5yESbekTF3xLiQX - ZZZfXt0S/nzFp3f2Oux3W7/ydvZ8XSd8+s+wm5oqEcSV9n+5n3ENZbt1A/wgnGI3 - oWrv0yRB9HugzTIGPpI1AQv9Z4p8E44RrB74/uTxYwb9+4yvpuz/fzTt3Gz+Kzc4 - 4fGGq8VpGMFj6AE65ZcOAHHUJe4VuoreBXLYDJcHl2WPIdNKDGscFjElDneLRhWQ - DfxekDJIQMWCjyBEXacfP6cc9U8Qld6TuVcwi1P2xb8tBDD4MIFL/psfzUhfv1Lw - O/XZEffJxCqkQn7dsCYy3wpaTjb6XmJ5j0Dbml4f0Bv40Y1mjlAf7C662Mbuguf6 - ewIDAQAB - -----END PUBLIC KEY----- - secret: my_secret_key ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - labels: - konghq.com/credential: basic-auth - name: basic-auth-example-user -stringData: - password: my_basic_password - username: my_basic_user ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - labels: - konghq.com/credential: acl - name: acl-group-example-user -stringData: - group: acl_group ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - labels: - konghq.com/credential: mtls-auth - name: mtls-auth-example-user -stringData: - id: cce8c384-721f-4f58-85dd-50834e3e733a - subject_name: example-user@example.com -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: ca-cert-a672ab52d2341203bd70116b456413d7ac3ffc162abbf -stringData: - ca.crt: | - -----BEGIN CERTIFICATE----- - MIIBfDCCASKgAwIBAgIRAJqcZC1VSvSQLMN1+7yAeswwCgYIKoZIzj0EAwIwHDEa - MBgGA1UEAxMRRGVtbyBLb25nIFJvb3QgQ0EwHhcNMjIwNjEzMTMzNzMzWhcNMjcw - NjEzMTkzNzMzWjAcMRowGAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTBZMBMGByqG - SM49AgEGCCqGSM49AwEHA0IABOGR89IyhreSHRAi6wp9a5DBIDp4YYSdWzuEdlNx - 7pX1G4T7x68xUXJZXRUPFyT8Xzn5KwCJm8RVT+nAhrsUx6SjRTBDMA4GA1UdDwEB - /wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBQ9CUiOPhjp7KD2 - ScRDxX4IzDOrNzAKBggqhkjOPQQDAgNIADBFAiEAw6Dov0c0L++1W9VufAfSMdNR - PSDfPU0MiUiG59/VIBICIEFn/6c5eQc3hUUBL74/RmNT2b1zxBmp7RiPXJAnAAwJ - -----END CERTIFICATE----- - ca.digest: f1baffe9fe9cf8497e38a4271d67fab44423678b7e7c0f677a50f37c113d81b5 -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: ca-cert-a4f087c2ee00e6d43cfb4f6884fc1e79f7e6e08e84471 -stringData: - ca.crt: | - -----BEGIN CERTIFICATE----- - MIIBqTCCAVCgAwIBAgIQb5LqGa9gS3+Mc2ntWfSoJjAKBggqhkjOPQQDAjAcMRow - GAYDVQQDExFEZW1vIEtvbmcgUm9vdCBDQTAeFw0yMjA2MTMxMzM5MTVaFw0yMzA2 - MTMxOTM5MTVaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBSb290IEludGVybWVkaWF0 - ZTEgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQImvnSuvXkGy88lvx8a7of - e0MEMRI2siVvybvWXNpeXXlixgaq7weJ7pewf3HywfO68Va6kn8ehWh7s0D7SLHM - o2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4E - FgQUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwHwYDVR0jBBgwFoAUPQlIjj4Y6eyg9knE - Q8V+CMwzqzcwCgYIKoZIzj0EAwIDRwAwRAIgNZ+JPA1OqF5DsPapAZ2YsUOgIpn3 - ZbQuYKCAV0SD4EcCIFnfA5rWrc1AgtUw5inJQqJQRNgoPuC14vACqI48BiRl - -----END CERTIFICATE----- - ca.digest: dbef7ed285fb292e24f84ffba93c48d92fa322387d85469c460c655abedd5308 -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: ca-cert-6b095c7ff377b01252a4dfec59c582fe32934fa7ed0cf -stringData: - ca.crt: | - -----BEGIN CERTIFICATE----- - MIIBujCCAV+gAwIBAgIRAMkGpj7WZf+2RFE/q7ZhejEwCgYIKoZIzj0EAwIwKjEo - MCYGA1UEAxMfRGVtbyBLb25nIFJvb3QgSW50ZXJtZWRpYXRlMSBDQTAeFw0yMjA2 - MTMxMzQwNTFaFw0yMjEyMTMwNDQwNTFaMCoxKDAmBgNVBAMTH0RlbW8gS29uZyBS - b290IEludGVybWVkaWF0ZTIgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQB - my/zhZ3F2HvHFqtQzuD3lXX8SeYakxiBQvaGkGSLKD67N3vh7iC2rTSdj/vAs8ws - Y9X+mXzS6GDKC8PbSX6xo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgw - BgEB/wIBADAdBgNVHQ4EFgQURwCm53YPStZoAMfnVyknH4IgZa4wHwYDVR0jBBgw - FoAUhuxCKmCSvZWf95+iZ+Wsz9DJJVMwCgYIKoZIzj0EAwIDSQAwRgIhAN1pkUKc - azM4PiXOnkILB2KBDIF4XpHf+4ThDMODzXP8AiEA45KXA3qMrRPQV1oBfWZ3hLgX - gxUhveuHBXMWnzUbn6U= - -----END CERTIFICATE----- - ca.digest: 45b2b6dd9d4102955b1b1e4b540e677f140521462ed4f22fa5a713863ca84600 -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: cert-0ee0e1584c8637facac95bd5fce315367dee124c0086d41e -stringData: - tls.crt: |- - -----BEGIN CERTIFICATE----- - MIIECTCCAvGgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyAwDQYJKoZIhvcNAQEL - BQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM - CUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY - MBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u - Z2hxLmNvbTAeFw0yMTAxMTUxMTE5NDNaFw0yMjA1MzAxMTE5NDNaMIGRMQswCQYD - VQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx - EDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFzAVBgNVBAMMDnBy - b3h5LmtvbmcubGFuMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29uZ2hxLmNvbTCCASIw - DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJUbKiqoCK1BTNk/7l42n6ukyTEu - eLyB23e/90PzT/oz8wZzgwTodzbFAS2VtFr1EKqFzor0DrXp9CLnebOdiAR3I6LD - /WY/x0KW3lx3F35fGiUOSLPTH8zeiDTMx11CcKDxesA+M2/s5q0igkOQ4z4w3voz - m5a52IcQTSA8K5knNU1qUZBLpc+khxFcaheEK1jsISJJhcdizZBfGdk8S1vpyj5F - uCZ7oaRvNA6imHjSJwpgo36zd84TgrIgVj9R4QtJysWy/X+bbaKUiKBWwAtd4+DT - EP90l/ny9szu2fijk4/6k1ntXufGTyvM+J0/qJ13e99TVYOVanITnpTO+6cCAwEA - AaNWMFQwHwYDVR0jBBgwFoAUdskpf0wJRQxjtzQFZciWmUfl2bcwCQYDVR0TBAIw - ADALBgNVHQ8EBAMCBPAwGQYDVR0RBBIwEIIOcHJveHkua29uZy5sYW4wDQYJKoZI - hvcNAQELBQADggEBAJVrTWQRQzNtypa9OXFYADm8Fay1VMop3BY2kh0tfYgQEJ/4 - pJUj6CaszQZ/Aix6LaPnXFcoPCDqqv00mgju86PMamr/zA9USXk8eTmzJkp5RklS - GdqiXboqESiQVvaNz3kdW7wgNz4FwaGCzkEi/dcc2LdtzLpWizx+TlxMMqjonUUM - ovZgZo+OlhWRsDVT/qy5SFtA0vlVNtdBr2egXb1H7J8UDC+fax/iKa7+fBUHZOO9 - Fk9U8bxgfQ+jPIVVL8CfAtR68Sos7NpWH0S2emqZRnQvf0MSNdkTQKWn4qR9sckj - Ewxs5FbrMmgCOgwk1PtgRmdP3RME0HwK/B03saQ= - -----END CERTIFICATE----- - tls.key: |- - -----BEGIN PRIVATE KEY----- - MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCVGyoqqAitQUzZ - P+5eNp+rpMkxLni8gdt3v/dD80/6M/MGc4ME6Hc2xQEtlbRa9RCqhc6K9A616fQi - 53mznYgEdyOiw/1mP8dClt5cdxd+XxolDkiz0x/M3og0zMddQnCg8XrAPjNv7Oat - IoJDkOM+MN76M5uWudiHEE0gPCuZJzVNalGQS6XPpIcRXGoXhCtY7CEiSYXHYs2Q - XxnZPEtb6co+Rbgme6GkbzQOoph40icKYKN+s3fOE4KyIFY/UeELScrFsv1/m22i - lIigVsALXePg0xD/dJf58vbM7tn4o5OP+pNZ7V7nxk8rzPidP6idd3vfU1WDlWpy - E56UzvunAgMBAAECggEAcq7lHNAHdHLgT8yrY41x/AwPryNGO/9JNW7SGVKAdjoU - tyaLZHAEmXynLk+R28/YFMA8H4Yd9m9OlrYhVjRZFM4p+5vxP/7YHPB7cPUsfcda - DZxR8PX25JVYf/vtb16V0ERLnKd62qCEwC/lr2A2WHQwXJLrHeAtmZzBJYUCJ5Xj - Dv1ZhyFjknswaV0vGXe6njTI6CzMQDTGysoagpCCo7RWgzjLREg2BGWd2UQpY4AW - nYAP4QNt82UMQbgIqsEMj64mzS9Q+o1P84J1naSP5sCI22LeFRp6iezZc+D8EH/5 - RNONGSNWl3g6bsvN1VywYwjWn+waD3XAjXUu+peUgQKBgQDDu1QP28oSMKivHdfo - kQ1HrTNBRc9eWeAMZFuIbbPLN8rdEibpOm3DwTqithnahqS0NLOsBnXNtuLw1Qr/ - zmOzn0yDO5XG8dlKr9vqWeBLdcRydLJBZwqEzWf4JwwwgfK3rItRaIbnAxnGUTS5 - SrrhNfBAIGS9jx5X2kvLC7hFQQKBgQDDBIrpLTIjRDloWZcu03z9Bhb8jQCyGb5C - 4MYs+duCnQIdNq/+maPspJzbVmF4b6S1zIPweI3fMvMeqRTbuf+drpElst1buFTO - P0UMMn4V+4qGIOOkIy5JIKwR8sJD9tNDUPtxuDEotTB9IyWx6pdmCFz5v/bggDCu - reoqflL+5wKBgQCDvb+L2QS+j4/KJk0flRoaJ2K7SVCVEesyjA3r2uLMImZhvAkC - rDgbLSDZSbZHFp8fR+WzILoD11gSf2Ki4PjMeqkWH3HlcP0vPwTHTO0h/UdXPmKI - kOFMl7CmHyoeMCj9JZ60EaXTMYwUpq3VFY6JbTOjBeqoh/8FZMHlDaNewQKBgCHg - ECEg8KyflTlDFrfTlMp+3E9STuShBCOp18LIRBEUJOHeNgQLvCXHElgnURcSjZHm - zKRgzIQQ3Zpd1Hm2fWhuglgCEeF0y4ZoBx5vRueaoh1aaTCBy/B39GvJt2UG4vu2 - fXbrf96KWrnh+RJGpbXbjgr0BXZJzisJmrt25gPRAoGBAI3c+INpQXwrE+LBzCPu - LwIVvkm5NpeIlKQtDNrqG1QvUhqyZ2/Xitc4FyiccW7WHxkGKGZyj7GbmpqEOnyY - iVku0LSftZgycet2uMdp0HaVAgi5S6aVf5yN0U/8R5ToxcbuEfqwrBIyRgse8lx3 - NNSvLxPAempmiFPSk9AtobYV - -----END PRIVATE KEY----- -type: kubernetes.io/tls ---- -apiVersion: v1 -kind: Secret -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: cert-b12464ec431576239dd9cc2545d528f6cbdbd988cf076323 -stringData: - tls.crt: |- - -----BEGIN CERTIFICATE----- - MIIFeDCCBGCgAwIBAgIUAusYGP9BwoLFFAJdB/jY6eUzUyQwDQYJKoZIhvcNAQEL - BQAwgZIxCzAJBgNVBAYTAlVLMRIwEAYDVQQIDAlIYW1wc2hpcmUxEjAQBgNVBAcM - CUFsZGVyc2hvdDEQMA4GA1UECgwHS29uZyBVSzEQMA4GA1UECwwHU3VwcG9ydDEY - MBYGA1UEAwwPU3VwcG9ydCBSb290IENBMR0wGwYJKoZIhvcNAQkBFg5zdHVAa29u - Z2hxLmNvbTAeFw0yMTAxMjAxNTA0NDVaFw0yMjAxMjAxNTA0NDVaMIGQMQswCQYD - VQQGEwJVSzESMBAGA1UECAwJSGFtcHNoaXJlMRIwEAYDVQQHDAlBbGRlcnNob3Qx - EDAOBgNVBAoMB0tvbmcgVUsxEDAOBgNVBAsMB1N1cHBvcnQxFjAUBgNVBAMMDW10 - bHMtY29uc3VtZXIxHTAbBgkqhkiG9w0BCQEWDnN0dUBrb25naHEuY29tMIICIjAN - BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1/+83/YNiEVKYvcuVwYGve6afsg1 - BYCn1+E9Uwgh0uwAenT/DKB8NhqoVxc7cZ2HaTI146IGmFICmctlTWvLPLglHmTo - byOUV6tIJAjvzyEOpC458hLGgbv8mhGXJWPxBVu7Wy6Hapz2bk0cEscfL7PHKaRu - 3D6r8/zbhhWAqe4EIt+NVYT6baaYBs7bPZQXs/sluKI+DNYuDeaAmoSuCc4ein6z - 0xDqCSMmPebzjns03ttB29vWL3eYY9dvgoCd+CPhXT/C4CHtvKbH+hOQYDtVF6MO - 1mmABAQTQWMR/00+QI0xtvuXtEPurla5dA0TN6ddCTOOcILKx62z5oc3Kqr+nHHa - 71zNzARUVaZ2vy1pRVr0DZgB7KqcFXhy/oy8IpmxUR1ASBDZl6B6RKrdQwvgLgmn - 3M/roNLAU+3nz4itpt/zf+X0suwdthrflic1R68z1SlYbyoGARWkZ/pOl6kLNVK2 - OsqQuICaajnW7t1oDd7z1+3hm+uoryDwvG6f3T9ZvWjKXYcKg7b+BjbFdahbDywD - PgnhSz9AaoVWhR+GHIPrjRClMpEkra/yGJFvH3UpXhgg9d0DrLZE51Z75a9SvnAj - vdLuNhx4bJbwLBgNGsJMkupzBrw4iCfbKFcBbP8o0Xjtarj7T/mkWuQ1GjWqfyrD - 55NecBPNw5C9BR0CAwEAAaOBxTCBwjAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQE - AwIFoDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgQ2xpZW50IENl - cnRpZmljYXRlMB0GA1UdDgQWBBSV3F+eicU8SVT4LcDJ6eMzP0todzAfBgNVHSME - GDAWgBR2ySl/TAlFDGO3NAVlyJaZR+XZtzAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0l - BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4IBAQB5L0OZ - WELG9Pw6Ol1BsZYgpLR4PGNBB9dKm/9dd+q+ohZVFCfXcjZ3YOU1vh/HHQrALRNY - I58JxcVCOx/qIW2uA0iSCqIT0sNb9cJLxfZf7X+BzPPPnu0ugUJp7GzLNnHitrLC - Xb1nmmefwgraNzp+a5IrR8RcQG1mYDuS+2HK/rybo22XcCxhob8OiDEn8+ytkKyQ - Ipmrf9D+/68/ih6az0w1aakASMmFe8z/p6VgVQkCySCWWFG525BRdGmSImqVZ4xa - aQFN3L+oN+JJcCFTthLOAYo32JH+xLMz7PokzSL84g3b68h59hXDoMSwB10GthL5 - T8tqV6i5miKWwvfZ - -----END CERTIFICATE----- - tls.key: |- - -----BEGIN RSA PRIVATE KEY----- - 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 - -----END RSA PRIVATE KEY----- -type: kubernetes.io/tls ---- -apiVersion: configuration.konghq.com/v1 -consumerGroups: -- example-consumer-group -credentials: -- key-auth-example-user -- jwt-auth-example-user -- basic-auth-example-user -- acl-group-example-user -- mtls-auth-example-user -custom_id: "1234567890" -kind: KongConsumer -metadata: - annotations: - konghq.com/plugins: example-user-rate-limiting-advanced - kubernetes.io/ingress.class: kong - name: example-user -username: example-user ---- -apiVersion: configuration.konghq.com/v1beta1 -kind: KongConsumerGroup -metadata: - annotations: - kubernetes.io/ingress.class: kong - name: example-consumer-group ---- diff --git a/kong2kic/testdata/route-gw-v2-output-expected.yaml b/kong2kic/testdata/route-gw-v2-output-expected.yaml new file mode 100644 index 000000000..c6a7cf942 --- /dev/null +++ b/kong2kic/testdata/route-gw-v2-output-expected.yaml @@ -0,0 +1,189 @@ +apiVersion: configuration.konghq.com/v1 +config: + aws_key: my_key + aws_region: us-west-2 + aws_secret: my_secret + function_name: my_function +kind: KongPlugin +metadata: + annotations: + kubernetes.io/ingress.class: kong + name: simple-service--route-thisisaveryvery-long-6d6e69918e +plugin: aws-lambda +--- +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: HTTPRoute +metadata: + name: simple-service-simple-route +spec: + parentRefs: + - name: kong + rules: + - backendRefs: + - name: simple-service + port: 8080 + matches: + - path: + type: PathPrefix + value: /r1 +--- +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: HTTPRoute +metadata: + annotations: + konghq.com/https-redirect-status-code: "302" + konghq.com/preserve-host: "true" + konghq.com/regex-priority: "1" + konghq.com/snis: example.com + konghq.com/strip-path: "false" + konghq.com/tags: version:v1 + name: simple-service--route-thisisaveryvery-long-b00bc5bc73 +spec: + hostnames: + - example.com + - another-example.com + - yet-another-example.com + parentRefs: + - name: kong + rules: + - backendRefs: + - name: simple-service + port: 8080 + filters: + - extensionRef: + group: configuration.konghq.com + kind: KongPlugin + name: simple-service--route-thisisaveryvery-long-6d6e69918e + type: ExtensionRef + matches: + - headers: + - name: x-another-header + type: Exact + value: first-header-value,second-header-value + - name: x-my-header + type: RegularExpression + value: foos?bar$ + method: GET + path: + type: RegularExpression + value: /v1/example/?$ + - backendRefs: + - name: simple-service + port: 8080 + filters: + - extensionRef: + group: configuration.konghq.com + kind: KongPlugin + name: simple-service--route-thisisaveryvery-long-6d6e69918e + type: ExtensionRef + matches: + - headers: + - name: x-another-header + type: Exact + value: first-header-value,second-header-value + - name: x-my-header + type: RegularExpression + value: foos?bar$ + method: POST + path: + type: RegularExpression + value: /v1/example/?$ + - backendRefs: + - name: simple-service + port: 8080 + filters: + - extensionRef: + group: configuration.konghq.com + kind: KongPlugin + name: simple-service--route-thisisaveryvery-long-6d6e69918e + type: ExtensionRef + matches: + - headers: + - name: x-another-header + type: Exact + value: first-header-value,second-header-value + - name: x-my-header + type: RegularExpression + value: foos?bar$ + method: GET + path: + type: PathPrefix + value: /v1/another-example + - backendRefs: + - name: simple-service + port: 8080 + filters: + - extensionRef: + group: configuration.konghq.com + kind: KongPlugin + name: simple-service--route-thisisaveryvery-long-6d6e69918e + type: ExtensionRef + matches: + - headers: + - name: x-another-header + type: Exact + value: first-header-value,second-header-value + - name: x-my-header + type: RegularExpression + value: foos?bar$ + method: POST + path: + type: PathPrefix + value: /v1/another-example + - backendRefs: + - name: simple-service + port: 8080 + filters: + - extensionRef: + group: configuration.konghq.com + kind: KongPlugin + name: simple-service--route-thisisaveryvery-long-6d6e69918e + type: ExtensionRef + matches: + - headers: + - name: x-another-header + type: Exact + value: first-header-value,second-header-value + - name: x-my-header + type: RegularExpression + value: foos?bar$ + method: GET + path: + type: PathPrefix + value: /v1/yet-another-example + - backendRefs: + - name: simple-service + port: 8080 + filters: + - extensionRef: + group: configuration.konghq.com + kind: KongPlugin + name: simple-service--route-thisisaveryvery-long-6d6e69918e + type: ExtensionRef + matches: + - headers: + - name: x-another-header + type: Exact + value: first-header-value,second-header-value + - name: x-my-header + type: RegularExpression + value: foos?bar$ + method: POST + path: + type: PathPrefix + value: /v1/yet-another-example +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + konghq.com/tags: simple-service + name: simple-service +spec: + ports: + - port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app: simple-service +--- diff --git a/kong2kic/testdata/route-gw-v3-output-expected.yaml b/kong2kic/testdata/route-gw-v3-output-expected.yaml new file mode 100644 index 000000000..f757a6c9d --- /dev/null +++ b/kong2kic/testdata/route-gw-v3-output-expected.yaml @@ -0,0 +1,189 @@ +apiVersion: configuration.konghq.com/v1 +config: + aws_key: my_key + aws_region: us-west-2 + aws_secret: my_secret + function_name: my_function +kind: KongPlugin +metadata: + annotations: + kubernetes.io/ingress.class: kong + name: simple-service--route-thisisaveryvery-long-6d6e69918e +plugin: aws-lambda +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: simple-service-simple-route +spec: + parentRefs: + - name: kong + rules: + - backendRefs: + - name: simple-service + port: 8080 + matches: + - path: + type: PathPrefix + value: /r1 +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + annotations: + konghq.com/https-redirect-status-code: "302" + konghq.com/preserve-host: "true" + konghq.com/regex-priority: "1" + konghq.com/snis: example.com + konghq.com/strip-path: "false" + konghq.com/tags: version:v1 + name: simple-service--route-thisisaveryvery-long-b00bc5bc73 +spec: + hostnames: + - example.com + - another-example.com + - yet-another-example.com + parentRefs: + - name: kong + rules: + - backendRefs: + - name: simple-service + port: 8080 + filters: + - extensionRef: + group: configuration.konghq.com + kind: KongPlugin + name: simple-service--route-thisisaveryvery-long-6d6e69918e + type: ExtensionRef + matches: + - headers: + - name: x-another-header + type: Exact + value: first-header-value,second-header-value + - name: x-my-header + type: RegularExpression + value: foos?bar$ + method: GET + path: + type: RegularExpression + value: /v1/example/?$ + - backendRefs: + - name: simple-service + port: 8080 + filters: + - extensionRef: + group: configuration.konghq.com + kind: KongPlugin + name: simple-service--route-thisisaveryvery-long-6d6e69918e + type: ExtensionRef + matches: + - headers: + - name: x-another-header + type: Exact + value: first-header-value,second-header-value + - name: x-my-header + type: RegularExpression + value: foos?bar$ + method: POST + path: + type: RegularExpression + value: /v1/example/?$ + - backendRefs: + - name: simple-service + port: 8080 + filters: + - extensionRef: + group: configuration.konghq.com + kind: KongPlugin + name: simple-service--route-thisisaveryvery-long-6d6e69918e + type: ExtensionRef + matches: + - headers: + - name: x-another-header + type: Exact + value: first-header-value,second-header-value + - name: x-my-header + type: RegularExpression + value: foos?bar$ + method: GET + path: + type: PathPrefix + value: /v1/another-example + - backendRefs: + - name: simple-service + port: 8080 + filters: + - extensionRef: + group: configuration.konghq.com + kind: KongPlugin + name: simple-service--route-thisisaveryvery-long-6d6e69918e + type: ExtensionRef + matches: + - headers: + - name: x-another-header + type: Exact + value: first-header-value,second-header-value + - name: x-my-header + type: RegularExpression + value: foos?bar$ + method: POST + path: + type: PathPrefix + value: /v1/another-example + - backendRefs: + - name: simple-service + port: 8080 + filters: + - extensionRef: + group: configuration.konghq.com + kind: KongPlugin + name: simple-service--route-thisisaveryvery-long-6d6e69918e + type: ExtensionRef + matches: + - headers: + - name: x-another-header + type: Exact + value: first-header-value,second-header-value + - name: x-my-header + type: RegularExpression + value: foos?bar$ + method: GET + path: + type: PathPrefix + value: /v1/yet-another-example + - backendRefs: + - name: simple-service + port: 8080 + filters: + - extensionRef: + group: configuration.konghq.com + kind: KongPlugin + name: simple-service--route-thisisaveryvery-long-6d6e69918e + type: ExtensionRef + matches: + - headers: + - name: x-another-header + type: Exact + value: first-header-value,second-header-value + - name: x-my-header + type: RegularExpression + value: foos?bar$ + method: POST + path: + type: PathPrefix + value: /v1/yet-another-example +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + konghq.com/tags: simple-service + name: simple-service +spec: + ports: + - port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app: simple-service +--- diff --git a/kong2kic/testdata/route-ingress-output-expected.yaml b/kong2kic/testdata/route-ingress-output-expected.yaml new file mode 100644 index 000000000..4949b2e51 --- /dev/null +++ b/kong2kic/testdata/route-ingress-output-expected.yaml @@ -0,0 +1,136 @@ +apiVersion: configuration.konghq.com/v1 +config: + aws_key: my_key + aws_region: us-west-2 + aws_secret: my_secret + function_name: my_function +kind: KongPlugin +metadata: + annotations: + kubernetes.io/ingress.class: kong + name: simple-service--route-thisisaveryvery-long-6d6e69918e +plugin: aws-lambda +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: simple-service-simple-route +spec: + ingressClassName: kong + rules: + - http: + paths: + - backend: + service: + name: simple-service + port: + number: 8080 + path: /r1 + pathType: ImplementationSpecific +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + konghq.com/headers.x-another-header: first-header-value,second-header-value + konghq.com/headers.x-my-header: ~*foos?bar$ + konghq.com/https-redirect-status-code: "302" + konghq.com/methods: GET,POST + konghq.com/plugins: simple-service--route-thisisaveryvery-long-6d6e69918e + konghq.com/preserve-host: "true" + konghq.com/protocols: http,https + konghq.com/regex-priority: "1" + konghq.com/snis: example.com + konghq.com/strip-path: "false" + konghq.com/tags: version:v1 + name: simple-service--route-thisisaveryvery-long-b00bc5bc73 +spec: + ingressClassName: kong + rules: + - host: example.com + http: + paths: + - backend: + service: + name: simple-service + port: + number: 8080 + path: /~/v1/example/?$ + pathType: ImplementationSpecific + - backend: + service: + name: simple-service + port: + number: 8080 + path: /v1/another-example + pathType: ImplementationSpecific + - backend: + service: + name: simple-service + port: + number: 8080 + path: /v1/yet-another-example + pathType: ImplementationSpecific + - host: another-example.com + http: + paths: + - backend: + service: + name: simple-service + port: + number: 8080 + path: /~/v1/example/?$ + pathType: ImplementationSpecific + - backend: + service: + name: simple-service + port: + number: 8080 + path: /v1/another-example + pathType: ImplementationSpecific + - backend: + service: + name: simple-service + port: + number: 8080 + path: /v1/yet-another-example + pathType: ImplementationSpecific + - host: yet-another-example.com + http: + paths: + - backend: + service: + name: simple-service + port: + number: 8080 + path: /~/v1/example/?$ + pathType: ImplementationSpecific + - backend: + service: + name: simple-service + port: + number: 8080 + path: /v1/another-example + pathType: ImplementationSpecific + - backend: + service: + name: simple-service + port: + number: 8080 + path: /v1/yet-another-example + pathType: ImplementationSpecific +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + konghq.com/tags: simple-service + name: simple-service +spec: + ports: + - port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app: simple-service +--- diff --git a/kong2kic/testdata/route-input.yaml b/kong2kic/testdata/route-input.yaml new file mode 100644 index 000000000..d92d271bd --- /dev/null +++ b/kong2kic/testdata/route-input.yaml @@ -0,0 +1,47 @@ +services: + - name: simple-service + port: 8080 + tags: + - simple-service + routes: + - name: simple-route + paths: + - /r1 + - name: _route_thisISAveryvery_long_+name_toVALIDATEthat(the slugify functionality w0rks4s3xp3ct3d)_ + methods: + - GET + - POST + hosts: + - example.com + - another-example.com + - yet-another-example.com + paths: + - ~/v1/example/?$ + - /v1/another-example + - /v1/yet-another-example + protocols: + - http + - https + headers: + x-my-header: + - ~*foos?bar$ + x-another-header: + - first-header-value + - second-header-value + regex_priority: 1 + strip_path: false + preserve_host: true + tags: + - version:v1 + https_redirect_status_code: 302 + snis: + - example.com + sources: + - ip: 192.168.0.1 + plugins: + - name: aws-lambda + config: + aws_key: my_key + aws_secret: my_secret + function_name: my_function + aws_region: us-west-2 \ No newline at end of file diff --git a/kong2kic/testdata/service-input.yaml b/kong2kic/testdata/service-input.yaml new file mode 100644 index 000000000..1f31d6566 --- /dev/null +++ b/kong2kic/testdata/service-input.yaml @@ -0,0 +1,40 @@ +services: + - name: complex-service + url: http://example-api.com + protocol: http + host: example-api.com + port: 80 + path: /v1 + retries: 5 + connect_timeout: 5000 + write_timeout: 60000 + read_timeout: 60000 + enabled: true + client_certificate: 4e3ad2e4-0bc4-4638-8e34-c84a417ba39b + tags: + - example + - api + plugins: + - name: cors + config: + origins: + - http://mockbin.com + methods: + - GET + - POST + headers: + - Accept + - Accept-Version + - Content-Length + - Content-MD5 + - Content-Type + - Date + - X-Auth-Token + exposed_headers: + - X-Auth-Token + credentials: true + max_age: 3600 + tags: + - cors-complex-service + - name: simple-service + port: 8080 \ No newline at end of file diff --git a/kong2kic/testdata/service-output-expected.yaml b/kong2kic/testdata/service-output-expected.yaml new file mode 100644 index 000000000..cfb44d736 --- /dev/null +++ b/kong2kic/testdata/service-output-expected.yaml @@ -0,0 +1,61 @@ +apiVersion: configuration.konghq.com/v1 +config: + credentials: true + exposed_headers: + - X-Auth-Token + headers: + - Accept + - Accept-Version + - Content-Length + - Content-MD5 + - Content-Type + - Date + - X-Auth-Token + max_age: 3600 + methods: + - GET + - POST + origins: + - http://mockbin.com +kind: KongPlugin +metadata: + annotations: + konghq.com/tags: cors-complex-service + kubernetes.io/ingress.class: kong + name: complex-service-cors +plugin: cors +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + konghq.com/client-cert: 4e3ad2e4-0bc4-4638-8e34-c84a417ba39b + konghq.com/connect-timeout: "5000" + konghq.com/path: /v1 + konghq.com/plugins: complex-service-cors + konghq.com/protocol: http + konghq.com/read-timeout: "60000" + konghq.com/retries: "5" + konghq.com/tags: example,api + konghq.com/write-timeout: "60000" + name: complex-service +spec: + externalName: example-api.com + ports: + - port: 80 + protocol: TCP + targetPort: 80 + type: ExternalName +--- +apiVersion: v1 +kind: Service +metadata: + name: simple-service +spec: + ports: + - port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app: simple-service +--- diff --git a/kong2kic/testdata/upstream-input.yaml b/kong2kic/testdata/upstream-input.yaml new file mode 100644 index 000000000..b5efdebb0 --- /dev/null +++ b/kong2kic/testdata/upstream-input.yaml @@ -0,0 +1,82 @@ + +services: + - name: simple-service + host: example-api.com + port: 80 +upstreams: + - name: example-api.com + algorithm: round-robin + hash_on: none + hash_fallback: none + hash_on_cookie_path: "/" + slots: 10000 + healthchecks: + passive: + type: http + healthy: + http_statuses: + - 200 + - 201 + - 202 + - 203 + - 204 + - 205 + - 206 + - 207 + - 208 + - 226 + - 300 + - 301 + - 302 + - 303 + - 304 + - 305 + - 306 + - 307 + - 308 + successes: 0 + unhealthy: + http_statuses: + - 429 + - 500 + - 503 + timeouts: 0 + http_failures: 0 + tcp_failures: 0 + active: + https_verify_certificate: true + healthy: + http_statuses: + - 200 + - 302 + successes: 0 + interval: 0 + unhealthy: + http_failures: 0 + http_statuses: + - 429 + - 404 + - 500 + - 501 + - 502 + - 503 + - 504 + - 505 + timeouts: 0 + tcp_failures: 0 + interval: 0 + type: http + concurrency: 10 + headers: + x-my-header: + - foo + - bar + x-another-header: + - bla + timeout: 1 + http_path: "/" + https_sni: example.com + threshold: 0 + tags: + - user-level + - low-priority \ No newline at end of file diff --git a/kong2kic/testdata/upstream-v2-output-expected.yaml b/kong2kic/testdata/upstream-v2-output-expected.yaml new file mode 100644 index 000000000..da33aef88 --- /dev/null +++ b/kong2kic/testdata/upstream-v2-output-expected.yaml @@ -0,0 +1,95 @@ +apiVersion: configuration.konghq.com/v1 +kind: KongIngress +metadata: + annotations: + konghq.com/tags: user-level,low-priority + kubernetes.io/ingress.class: kong + name: simple-service-upstream +upstream: + algorithm: round-robin + hash_fallback: none + hash_on: none + hash_on_cookie_path: / + healthchecks: + active: + concurrency: 10 + headers: + x-another-header: + - bla + x-my-header: + - foo + - bar + healthy: + http_statuses: + - 200 + - 302 + interval: 0 + successes: 0 + http_path: / + https_sni: example.com + https_verify_certificate: true + timeout: 1 + type: http + unhealthy: + http_failures: 0 + http_statuses: + - 429 + - 404 + - 500 + - 501 + - 502 + - 503 + - 504 + - 505 + interval: 0 + tcp_failures: 0 + timeouts: 0 + passive: + healthy: + http_statuses: + - 200 + - 201 + - 202 + - 203 + - 204 + - 205 + - 206 + - 207 + - 208 + - 226 + - 300 + - 301 + - 302 + - 303 + - 304 + - 305 + - 306 + - 307 + - 308 + successes: 0 + type: http + unhealthy: + http_failures: 0 + http_statuses: + - 429 + - 500 + - 503 + tcp_failures: 0 + timeouts: 0 + threshold: 0 + slots: 10000 +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + konghq.com/override: simple-service-upstream + name: simple-service +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: simple-service +--- diff --git a/kong2kic/testdata/upstream-v3-output-expected.yaml b/kong2kic/testdata/upstream-v3-output-expected.yaml new file mode 100644 index 000000000..253f9a5c3 --- /dev/null +++ b/kong2kic/testdata/upstream-v3-output-expected.yaml @@ -0,0 +1,91 @@ +apiVersion: configuration.konghq.com/v1beta1 +kind: KongUpstreamPolicy +metadata: + annotations: + konghq.com/tags: user-level,low-priority + name: simple-service-upstream +spec: + algorithm: round-robin + healthchecks: + active: + concurrency: 10 + headers: + x-another-header: + - bla + x-my-header: + - foo + - bar + healthy: + httpStatuses: + - 200 + - 302 + interval: 0 + successes: 0 + httpPath: / + httpsSni: example.com + httpsVerifyCertificate: true + timeout: 1 + type: http + unhealthy: + httpFailures: 0 + httpStatuses: + - 429 + - 404 + - 500 + - 501 + - 502 + - 503 + - 504 + - 505 + interval: 0 + tcpFailures: 0 + timeouts: 0 + passive: + healthy: + httpStatuses: + - 200 + - 201 + - 202 + - 203 + - 204 + - 205 + - 206 + - 207 + - 208 + - 226 + - 300 + - 301 + - 302 + - 303 + - 304 + - 305 + - 306 + - 307 + - 308 + successes: 0 + type: http + unhealthy: + httpFailures: 0 + httpStatuses: + - 429 + - 500 + - 503 + tcpFailures: 0 + timeouts: 0 + threshold: 0 + slots: 10000 +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + konghq.com/upstream-policy: simple-service-upstream + name: simple-service +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: simple-service +--- diff --git a/kong2kic/upstream.go b/kong2kic/upstream.go index 78cee7e67..b27af4bcc 100644 --- a/kong2kic/upstream.go +++ b/kong2kic/upstream.go @@ -5,212 +5,239 @@ import ( "strings" "github.com/kong/go-database-reconciler/pkg/file" + "github.com/kong/go-kong/kong" kicv1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1" kicv1beta1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1beta1" k8scorev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// UpstreamPolicy for KIC v3 +// Helper function to find the matching upstream +func findMatchingUpstream(serviceHost *string, upstreams []file.FUpstream) *file.FUpstream { + if serviceHost == nil { + return nil + } + for _, upstream := range upstreams { + if upstream.Name != nil && strings.EqualFold(*upstream.Name, *serviceHost) { + return &upstream + } + } + return nil +} + +// Helper function to convert HTTP statuses +func convertHTTPStatuses(statuses []int) []kicv1beta1.HTTPStatus { + if statuses == nil { + return nil + } + result := make([]kicv1beta1.HTTPStatus, len(statuses)) + for i, status := range statuses { + result[i] = kicv1beta1.HTTPStatus(status) + } + return result +} + +// Helper function to populate active healthcheck +func populateActiveHealthcheck(active *kong.ActiveHealthcheck) *kicv1beta1.KongUpstreamActiveHealthcheck { + if active == nil { + return nil + } + return &kicv1beta1.KongUpstreamActiveHealthcheck{ + Type: active.Type, + Concurrency: active.Concurrency, + HTTPPath: active.HTTPPath, + HTTPSSNI: active.HTTPSSni, + HTTPSVerifyCertificate: active.HTTPSVerifyCertificate, + Timeout: active.Timeout, + Headers: active.Headers, + Healthy: populateHealthcheckHealthy(active.Healthy), + Unhealthy: populateHealthcheckUnhealthy(active.Unhealthy), + } +} + +// Helper function to populate passive healthcheck +func populatePassiveHealthcheck(passive *kong.PassiveHealthcheck) *kicv1beta1.KongUpstreamPassiveHealthcheck { + if passive == nil { + return nil + } + return &kicv1beta1.KongUpstreamPassiveHealthcheck{ + Type: passive.Type, + Healthy: populateHealthcheckHealthy(passive.Healthy), + Unhealthy: populateHealthcheckUnhealthy(passive.Unhealthy), + } +} + +// Helper function to populate healthcheck healthy settings +func populateHealthcheckHealthy(healthy *kong.Healthy) *kicv1beta1.KongUpstreamHealthcheckHealthy { + if healthy == nil { + return nil + } + return &kicv1beta1.KongUpstreamHealthcheckHealthy{ + Interval: healthy.Interval, + Successes: healthy.Successes, + HTTPStatuses: convertHTTPStatuses(healthy.HTTPStatuses), + } +} + +// Helper function to populate healthcheck unhealthy settings +func populateHealthcheckUnhealthy(unhealthy *kong.Unhealthy) *kicv1beta1.KongUpstreamHealthcheckUnhealthy { + if unhealthy == nil { + return nil + } + return &kicv1beta1.KongUpstreamHealthcheckUnhealthy{ + HTTPFailures: unhealthy.HTTPFailures, + TCPFailures: unhealthy.TCPFailures, + Timeouts: unhealthy.Timeouts, + Interval: unhealthy.Interval, + HTTPStatuses: convertHTTPStatuses(unhealthy.HTTPStatuses), + } +} + +// Function to populate KIC Upstream Policy for KIC v3 func populateKICUpstreamPolicy( content *file.Content, service *file.FService, - k8sservice *k8scorev1.Service, + k8sService *k8scorev1.Service, kicContent *KICContent, ) { - if content.Upstreams != nil { - var kongUpstreamPolicy kicv1beta1.KongUpstreamPolicy - kongUpstreamPolicy.APIVersion = KICAPIVersionV1Beta1 - kongUpstreamPolicy.Kind = UpstreamPolicyKind - if service.Name != nil { - kongUpstreamPolicy.ObjectMeta.Name = calculateSlug(*service.Name + "-upstream") - } else { - log.Println("Service name is empty. This is not recommended." + - "Please, provide a name for the service before generating Kong Ingress Controller manifests.") - return - } + if service.Name == nil { + log.Println("Service name is empty. Please provide the necessary information.") + return + } + + // Find the matching upstream + upstream := findMatchingUpstream(service.Host, content.Upstreams) + if upstream == nil { + return + } - // Find the upstream (if any) whose name matches the service host and copy the upstream - // into kongUpstreamPolicy. Append the kongUpstreamPolicy to kicContent.KongUpstreamPolicies. - found := false - for _, upstream := range content.Upstreams { - if upstream.Name != nil && strings.EqualFold(*upstream.Name, *service.Host) { - found = true - // add an annotation to the k8sservice to link this kongUpstreamPolicy to it - k8sservice.ObjectMeta.Annotations["konghq.com/upstream-policy"] = kongUpstreamPolicy.ObjectMeta.Name - var threshold int - if upstream.Healthchecks != nil && upstream.Healthchecks.Threshold != nil { - threshold = int(*upstream.Healthchecks.Threshold) - } - var activeHealthyHTTPStatuses []kicv1beta1.HTTPStatus - var activeUnhealthyHTTPStatuses []kicv1beta1.HTTPStatus - var passiveHealthyHTTPStatuses []kicv1beta1.HTTPStatus - var passiveUnhealthyHTTPStatuses []kicv1beta1.HTTPStatus - - if upstream.Healthchecks != nil && - upstream.Healthchecks.Active != nil && - upstream.Healthchecks.Active.Healthy != nil { - activeHealthyHTTPStatuses = make([]kicv1beta1.HTTPStatus, len(upstream.Healthchecks.Active.Healthy.HTTPStatuses)) - for i, status := range upstream.Healthchecks.Active.Healthy.HTTPStatuses { - activeHealthyHTTPStatuses[i] = kicv1beta1.HTTPStatus(status) - } - } - - if upstream.Healthchecks != nil && - upstream.Healthchecks.Active != nil && - upstream.Healthchecks.Active.Unhealthy != nil { - activeUnhealthyHTTPStatuses = make([]kicv1beta1.HTTPStatus, - len(upstream.Healthchecks.Active.Unhealthy.HTTPStatuses)) - for i, status := range upstream.Healthchecks.Active.Unhealthy.HTTPStatuses { - activeUnhealthyHTTPStatuses[i] = kicv1beta1.HTTPStatus(status) - } - } - - if upstream.Healthchecks != nil && - upstream.Healthchecks.Passive != nil && - upstream.Healthchecks.Passive.Healthy != nil { - passiveHealthyHTTPStatuses = make([]kicv1beta1.HTTPStatus, len(upstream.Healthchecks.Passive.Healthy.HTTPStatuses)) - for i, status := range upstream.Healthchecks.Passive.Healthy.HTTPStatuses { - passiveHealthyHTTPStatuses[i] = kicv1beta1.HTTPStatus(status) - } - } - - if upstream.Healthchecks != nil && - upstream.Healthchecks.Passive != nil && - upstream.Healthchecks.Passive.Unhealthy != nil { - passiveUnhealthyHTTPStatuses = make([]kicv1beta1.HTTPStatus, - len(upstream.Healthchecks.Passive.Unhealthy.HTTPStatuses)) - for i, status := range upstream.Healthchecks.Passive.Unhealthy.HTTPStatuses { - passiveUnhealthyHTTPStatuses[i] = kicv1beta1.HTTPStatus(status) - } - } - - // populeate kongUpstreamPolicy.Spec with the - // non-nil attributes in upstream. - if upstream.Algorithm != nil { - kongUpstreamPolicy.Spec.Algorithm = upstream.Algorithm - } - if upstream.Slots != nil { - kongUpstreamPolicy.Spec.Slots = upstream.Slots - } - - if upstream.HashOn != nil && upstream.Algorithm != nil && *upstream.Algorithm == "consistent-hashing" { - kongUpstreamPolicy.Spec.HashOn = &kicv1beta1.KongUpstreamHash{ - Input: (*kicv1beta1.HashInput)(upstream.HashOn), - Header: upstream.HashOnHeader, - Cookie: upstream.HashOnCookie, - CookiePath: upstream.HashOnCookiePath, - QueryArg: upstream.HashOnQueryArg, - URICapture: upstream.HashOnURICapture, - } - } - if upstream.HashFallback != nil && upstream.Algorithm != nil && *upstream.Algorithm == "consistent-hashing" { - kongUpstreamPolicy.Spec.HashOnFallback = &kicv1beta1.KongUpstreamHash{ - Input: (*kicv1beta1.HashInput)(upstream.HashFallback), - Header: upstream.HashFallbackHeader, - QueryArg: upstream.HashFallbackQueryArg, - URICapture: upstream.HashFallbackURICapture, - } - } - if upstream.Healthchecks != nil { - kongUpstreamPolicy.Spec.Healthchecks = &kicv1beta1.KongUpstreamHealthcheck{ - Threshold: &threshold, - Active: &kicv1beta1.KongUpstreamActiveHealthcheck{ - Type: upstream.Healthchecks.Active.Type, - Concurrency: upstream.Healthchecks.Active.Concurrency, - HTTPPath: upstream.Healthchecks.Active.HTTPPath, - HTTPSSNI: upstream.Healthchecks.Active.HTTPSSni, - HTTPSVerifyCertificate: upstream.Healthchecks.Active.HTTPSVerifyCertificate, - Timeout: upstream.Healthchecks.Active.Timeout, - Headers: upstream.Healthchecks.Active.Headers, - Healthy: &kicv1beta1.KongUpstreamHealthcheckHealthy{ - Interval: upstream.Healthchecks.Active.Healthy.Interval, - Successes: upstream.Healthchecks.Active.Healthy.Successes, - HTTPStatuses: activeHealthyHTTPStatuses, - }, - Unhealthy: &kicv1beta1.KongUpstreamHealthcheckUnhealthy{ - HTTPFailures: upstream.Healthchecks.Active.Unhealthy.HTTPFailures, - TCPFailures: upstream.Healthchecks.Active.Unhealthy.TCPFailures, - Timeouts: upstream.Healthchecks.Active.Unhealthy.Timeouts, - Interval: upstream.Healthchecks.Active.Unhealthy.Interval, - HTTPStatuses: activeUnhealthyHTTPStatuses, - }, - }, - Passive: &kicv1beta1.KongUpstreamPassiveHealthcheck{ - Type: upstream.Healthchecks.Passive.Type, - Healthy: &kicv1beta1.KongUpstreamHealthcheckHealthy{ - HTTPStatuses: passiveHealthyHTTPStatuses, - Interval: upstream.Healthchecks.Passive.Healthy.Interval, - Successes: upstream.Healthchecks.Passive.Healthy.Successes, - }, - Unhealthy: &kicv1beta1.KongUpstreamHealthcheckUnhealthy{ - HTTPFailures: upstream.Healthchecks.Passive.Unhealthy.HTTPFailures, - HTTPStatuses: passiveUnhealthyHTTPStatuses, - TCPFailures: upstream.Healthchecks.Passive.Unhealthy.TCPFailures, - Timeouts: upstream.Healthchecks.Passive.Unhealthy.Timeouts, - Interval: upstream.Healthchecks.Passive.Unhealthy.Interval, - }, - }, - } - } + // Create KongUpstreamPolicy + kongUpstreamPolicy := kicv1beta1.KongUpstreamPolicy{ + TypeMeta: metav1.TypeMeta{ + APIVersion: KICAPIVersionV1Beta1, + Kind: UpstreamPolicyKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: calculateSlug(*service.Name + "-upstream"), + Annotations: make(map[string]string), + }, + } + + // Add an annotation to link the upstream policy to the k8s service + if k8sService.ObjectMeta.Annotations == nil { + k8sService.ObjectMeta.Annotations = make(map[string]string) + } + k8sService.ObjectMeta.Annotations["konghq.com/upstream-policy"] = kongUpstreamPolicy.ObjectMeta.Name + + // Populate the Upstream Policy Spec + populateKongUpstreamPolicySpec(upstream, &kongUpstreamPolicy) + + // Add tags to annotations + addTagsToAnnotations(upstream.Tags, kongUpstreamPolicy.ObjectMeta.Annotations) + + // Append the KongUpstreamPolicy to KIC content + kicContent.KongUpstreamPolicies = append(kicContent.KongUpstreamPolicies, kongUpstreamPolicy) +} + +// Helper function to populate KongUpstreamPolicy Spec +func populateKongUpstreamPolicySpec(upstream *file.FUpstream, policy *kicv1beta1.KongUpstreamPolicy) { + if upstream.Algorithm != nil { + policy.Spec.Algorithm = upstream.Algorithm + } + if upstream.Slots != nil { + policy.Spec.Slots = upstream.Slots + } + + if upstream.Algorithm != nil && *upstream.Algorithm == "consistent-hashing" { + if upstream.HashOn != nil { + policy.Spec.HashOn = &kicv1beta1.KongUpstreamHash{ + Input: (*kicv1beta1.HashInput)(upstream.HashOn), + Header: upstream.HashOnHeader, + Cookie: upstream.HashOnCookie, + CookiePath: upstream.HashOnCookiePath, + QueryArg: upstream.HashOnQueryArg, + URICapture: upstream.HashOnURICapture, } - if found { - kicContent.KongUpstreamPolicies = append(kicContent.KongUpstreamPolicies, kongUpstreamPolicy) + } + if upstream.HashFallback != nil { + policy.Spec.HashOnFallback = &kicv1beta1.KongUpstreamHash{ + Input: (*kicv1beta1.HashInput)(upstream.HashFallback), + Header: upstream.HashFallbackHeader, + QueryArg: upstream.HashFallbackQueryArg, + URICapture: upstream.HashFallbackURICapture, } } } + + // Handle healthchecks + if upstream.Healthchecks != nil { + var threshold int + if upstream.Healthchecks.Threshold != nil { + threshold = int(*upstream.Healthchecks.Threshold) + } + policy.Spec.Healthchecks = &kicv1beta1.KongUpstreamHealthcheck{ + Threshold: &threshold, + Active: populateActiveHealthcheck(upstream.Healthchecks.Active), + Passive: populatePassiveHealthcheck(upstream.Healthchecks.Passive), + } + } } -// KongIngress with upstream section for KIC v2 +// Function to populate KIC Upstream for KIC v2 func populateKICUpstream( content *file.Content, service *file.FService, - k8sservice *k8scorev1.Service, + k8sService *k8scorev1.Service, kicContent *KICContent, ) { - // add Kong specific configuration to the k8s service via a KongIngress resource - - if content.Upstreams != nil { - var kongIngress kicv1.KongIngress - kongIngress.APIVersion = KICAPIVersion - kongIngress.Kind = IngressKind - if service.Name != nil { - kongIngress.ObjectMeta.Name = calculateSlug(*service.Name + "-upstream") - } else { - log.Println("Service name is empty. This is not recommended." + - "Please, provide a name for the service before generating Kong Ingress Controller manifests.") - return - } - kongIngress.ObjectMeta.Annotations = map[string]string{IngressClass: ClassName} - - // add an annotation to the k8sservice to link this kongIngress to it - k8sservice.ObjectMeta.Annotations["konghq.com/override"] = kongIngress.ObjectMeta.Name - - // Find the upstream (if any) whose name matches the service host and copy the upstream - // into a kicv1.KongIngress resource. Append the kicv1.KongIngress to kicContent.KongIngresses. - found := false - for _, upstream := range content.Upstreams { - if upstream.Name != nil && strings.EqualFold(*upstream.Name, *service.Host) { - found = true - kongIngress.Upstream = &kicv1.KongIngressUpstream{ - HostHeader: upstream.HostHeader, - Algorithm: upstream.Algorithm, - Slots: upstream.Slots, - Healthchecks: upstream.Healthchecks, - HashOn: upstream.HashOn, - HashFallback: upstream.HashFallback, - HashOnHeader: upstream.HashOnHeader, - HashFallbackHeader: upstream.HashFallbackHeader, - HashOnCookie: upstream.HashOnCookie, - HashOnCookiePath: upstream.HashOnCookiePath, - HashOnQueryArg: upstream.HashOnQueryArg, - HashFallbackQueryArg: upstream.HashFallbackQueryArg, - HashOnURICapture: upstream.HashOnURICapture, - HashFallbackURICapture: upstream.HashFallbackURICapture, - } - } - } - if found { - kicContent.KongIngresses = append(kicContent.KongIngresses, kongIngress) - } + if service.Name == nil { + log.Println("Service name is empty. Please provide the necessary information.") + return + } + + // Find the matching upstream + upstream := findMatchingUpstream(service.Host, content.Upstreams) + if upstream == nil { + return + } + + // Create KongIngress + kongIngress := kicv1.KongIngress{ + TypeMeta: metav1.TypeMeta{ + APIVersion: KICAPIVersion, + Kind: IngressKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: calculateSlug(*service.Name + "-upstream"), + Annotations: map[string]string{IngressClass: ClassName}, + }, + Upstream: &kicv1.KongIngressUpstream{ + HostHeader: upstream.HostHeader, + Algorithm: upstream.Algorithm, + Slots: upstream.Slots, + Healthchecks: upstream.Healthchecks, + HashOn: upstream.HashOn, + HashFallback: upstream.HashFallback, + HashOnHeader: upstream.HashOnHeader, + HashFallbackHeader: upstream.HashFallbackHeader, + HashOnCookie: upstream.HashOnCookie, + HashOnCookiePath: upstream.HashOnCookiePath, + HashOnQueryArg: upstream.HashOnQueryArg, + HashFallbackQueryArg: upstream.HashFallbackQueryArg, + HashOnURICapture: upstream.HashOnURICapture, + HashFallbackURICapture: upstream.HashFallbackURICapture, + }, } + + // Add an annotation to link the KongIngress to the k8s service + if k8sService.ObjectMeta.Annotations == nil { + k8sService.ObjectMeta.Annotations = make(map[string]string) + } + k8sService.ObjectMeta.Annotations["konghq.com/override"] = kongIngress.ObjectMeta.Name + + // Add tags to annotations + addTagsToAnnotations(upstream.Tags, kongIngress.ObjectMeta.Annotations) + + // Append the KongIngress to KIC content + kicContent.KongIngresses = append(kicContent.KongIngresses, kongIngress) } diff --git a/kong2kic/utils.go b/kong2kic/utils.go new file mode 100644 index 000000000..6b0ba3308 --- /dev/null +++ b/kong2kic/utils.go @@ -0,0 +1,94 @@ +package kong2kic + +import ( + "encoding/json" + "log" + "strings" + + "github.com/kong/go-database-reconciler/pkg/file" + "github.com/kong/go-kong/kong" + kicv1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Helper function to add tags to annotations +func addTagsToAnnotations(tags []*string, annotations map[string]string) { + if tags != nil { + var tagList []string + for _, tag := range tags { + if tag != nil { + tagList = append(tagList, *tag) + } + } + if len(tagList) > 0 { + annotations["konghq.com/tags"] = strings.Join(tagList, ",") + } + } +} + +// Helper function to update the "konghq.com/plugins" annotation +func addPluginToAnnotations(pluginName string, annotations map[string]string) { + if existing, ok := annotations["konghq.com/plugins"]; ok && existing != "" { + annotations["konghq.com/plugins"] = existing + "," + pluginName + } else { + annotations["konghq.com/plugins"] = pluginName + } +} + +// Helper function to create a KongPlugin from a plugin +func createKongPlugin(plugin *file.FPlugin, ownerName string) (*kicv1.KongPlugin, error) { + if plugin.Name == nil { + log.Println("Plugin name is empty. Please provide a name for the plugin.") + return nil, nil + } + pluginName := *plugin.Name + kongPlugin := &kicv1.KongPlugin{ + TypeMeta: metav1.TypeMeta{ + APIVersion: KICAPIVersion, + Kind: KongPluginKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: calculateSlug(ownerName + "-" + pluginName), + Annotations: map[string]string{IngressClass: ClassName}, + }, + PluginName: pluginName, + } + + // Add tags to annotations + addTagsToAnnotations(plugin.Tags, kongPlugin.ObjectMeta.Annotations) + + // Populate enabled, runon, ordering, and protocols + if plugin.Enabled != nil { + kongPlugin.Disabled = !*plugin.Enabled + } + if plugin.RunOn != nil { + kongPlugin.RunOn = *plugin.RunOn + } + if plugin.Ordering != nil { + kongPlugin.Ordering = &kong.PluginOrdering{ + Before: plugin.Ordering.Before, + After: plugin.Ordering.After, + } + } + if plugin.Protocols != nil { + var protocols []string + for _, protocol := range plugin.Protocols { + if protocol != nil { + protocols = append(protocols, *protocol) + } + } + kongPlugin.Protocols = kicv1.StringsToKongProtocols(protocols) + } + + // Transform the plugin config + configJSON, err := json.Marshal(plugin.Config) + if err != nil { + return nil, err + } + kongPlugin.Config = apiextensionsv1.JSON{ + Raw: configJSON, + } + + return kongPlugin, nil +} From b09aa3eba7291220621f342bd91fbdcbfbe267db Mon Sep 17 00:00:00 2001 From: Prashansa Kulshrestha Date: Mon, 21 Oct 2024 18:25:34 +0530 Subject: [PATCH 3/7] feat: added validation for vault entities. (#1421) Online validation via deck gateway validate now supports validating vaults as well. --- validate/validate.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/validate/validate.go b/validate/validate.go index fe15ad100..256b33718 100644 --- a/validate/validate.go +++ b/validate/validate.go @@ -181,6 +181,9 @@ func (v *Validator) Validate(formatVersion semver.Version) []error { if err := v.entities(v.state.FilterChains, "filter_chains"); err != nil { allErr = append(allErr, err...) } + if err := v.entities(v.state.Vaults, "vaults"); err != nil { + allErr = append(allErr, err...) + } // validate routes format with Kong 3.x parsed30, err := semver.ParseTolerant(utils.FormatVersion30) From e09888dae84abc47fceaa87e778dccfda63e387e Mon Sep 17 00:00:00 2001 From: Gabriele Date: Mon, 21 Oct 2024 10:13:31 -0400 Subject: [PATCH 4/7] feat: support online validation with Konnect (#1335) * feat: support online validation with Konnect * tests: Added e2e tests for gateway validation with konnect. Also, this change adds a conditional that ensures that rbac flag used with konnect mode, gives an legible error to the user. * chore: lint fix * chore: removed workspace flag test as it is not supported with konnect * tests: added rbac-resources file * refactor: refactored tests and code to add all konnect validate usecases * chore: fixed workspace setting for Konnect check * chore: added mutually exclusive flags for konnect compatibility * chore: fixed logical error * chore: fixed descripancy in info due to preRun order in cobra * chore: added corrections based on PR review * removing unrelated code for vault validation --------- Co-authored-by: Prashansa Kulshrestha --- cmd/gateway_validate.go | 43 ++++++--- tests/integration/test_utils.go | 18 ++++ .../testdata/validate/konnect.yaml | 18 ++++ .../testdata/validate/konnect_1_1.yaml | 18 ++++ .../testdata/validate/konnect_invalid.yaml | 16 ++++ .../testdata/validate/konnect_no_version.yaml | 17 ++++ .../testdata/validate/rbac-resources.yaml | 93 ++++++++++++++++++ tests/integration/validate_test.go | 95 +++++++++++++++++++ 8 files changed, 307 insertions(+), 11 deletions(-) create mode 100644 tests/integration/testdata/validate/konnect.yaml create mode 100644 tests/integration/testdata/validate/konnect_1_1.yaml create mode 100644 tests/integration/testdata/validate/konnect_invalid.yaml create mode 100644 tests/integration/testdata/validate/konnect_no_version.yaml create mode 100644 tests/integration/testdata/validate/rbac-resources.yaml create mode 100644 tests/integration/validate_test.go diff --git a/cmd/gateway_validate.go b/cmd/gateway_validate.go index 271f2463d..455cec32a 100644 --- a/cmd/gateway_validate.go +++ b/cmd/gateway_validate.go @@ -27,9 +27,6 @@ var ( func executeValidate(cmd *cobra.Command, _ []string) error { mode := getMode(nil) - if validateOnline && mode == modeKonnect { - return fmt.Errorf("online validation not yet supported in konnect mode") - } _ = sendAnalytics("validate", "", mode) // read target file // this does json schema validation as well @@ -45,7 +42,7 @@ func executeValidate(cmd *cobra.Command, _ []string) error { ctx := cmd.Context() var kongClient *kong.Client if validateOnline { - kongClient, err = getKongClient(ctx, targetContent) + kongClient, err = getKongClient(ctx, targetContent, mode) if err != nil { return err } @@ -143,10 +140,14 @@ func executeValidate(cmd *cobra.Command, _ []string) error { return err } - if validateKonnectCompatibility { + if validateKonnectCompatibility || (mode == modeKonnect && validateOnline) { if errs := validate.KonnectCompatibility(targetContent); len(errs) != 0 { return validate.ErrorsWrapper{Errors: errs} } + + if validateCmdRBACResourcesOnly { + return fmt.Errorf("[rbac] not yet supported by konnect") + } } if validateOnline { @@ -212,7 +213,7 @@ this command unless --online flag is used. return preRunSilenceEventsFlag() } - if validateOnline { + if online { short = short + " (online)" long = long + "Validates against the Kong API, via communication with Kong. This increases the\n" + "time for validation but catches significant errors. No resource is created in Kong.\n" + @@ -255,6 +256,9 @@ this command unless --online flag is used. validateCmd.Flags().BoolVar(&validateKonnectCompatibility, "konnect-compatibility", false, "validate that the state file(s) are ready to be deployed to Konnect") + validateCmd.MarkFlagsMutuallyExclusive("konnect-compatibility", "workspace") + validateCmd.MarkFlagsMutuallyExclusive("konnect-compatibility", "rbac-resources-only") + if err := ensureGetAllMethods(); err != nil { panic(err.Error()) } @@ -285,9 +289,14 @@ func validateWithKong( return validator.Validate(parsedFormatVersion) } -func getKongClient(ctx context.Context, targetContent *file.Content) (*kong.Client, error) { +func getKongClient( + ctx context.Context, targetContent *file.Content, mode mode, +) (*kong.Client, error) { workspaceName := validateWorkspace if validateWorkspace != "" { + if mode == modeKonnect { + return nil, fmt.Errorf("[workspaces] not supported by Konnect - use control planes instead") + } // check if workspace exists workspaceName := getWorkspaceName(validateWorkspace, targetContent, false) workspaceExists, err := workspaceExists(ctx, rootConfig, workspaceName) @@ -299,10 +308,22 @@ func getKongClient(ctx context.Context, targetContent *file.Content) (*kong.Clie } } - wsConfig := rootConfig.ForWorkspace(workspaceName) - kongClient, err := reconcilerUtils.GetKongClient(wsConfig) - if err != nil { - return nil, err + var ( + kongClient *kong.Client + err error + ) + if mode == modeKonnect { + kongClient, err = GetKongClientForKonnectMode(ctx, &konnectConfig) + if err != nil { + return nil, err + } + dumpConfig.KonnectControlPlane = konnectControlPlane + } else { + wsConfig := rootConfig.ForWorkspace(workspaceName) + kongClient, err = reconcilerUtils.GetKongClient(wsConfig) + if err != nil { + return nil, err + } } return kongClient, nil } diff --git a/tests/integration/test_utils.go b/tests/integration/test_utils.go index d1d37f676..41a23b40e 100644 --- a/tests/integration/test_utils.go +++ b/tests/integration/test_utils.go @@ -374,3 +374,21 @@ func render(opts ...string) (string, error) { return stripansi.Strip(string(out)), cmdErr } + +func validate(online bool, opts ...string) error { + deckCmd := cmd.NewRootCmd() + + var args []string + if online { + args = []string{"gateway", "validate"} + } else { + args = []string{"file", "validate"} + } + + if len(opts) > 0 { + args = append(args, opts...) + } + deckCmd.SetArgs(args) + + return deckCmd.ExecuteContext(context.Background()) +} diff --git a/tests/integration/testdata/validate/konnect.yaml b/tests/integration/testdata/validate/konnect.yaml new file mode 100644 index 000000000..a9fa78b4d --- /dev/null +++ b/tests/integration/testdata/validate/konnect.yaml @@ -0,0 +1,18 @@ +_format_version: "3.0" +_konnect: + control_plane_name: default +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - name: r1 + id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + https_redirect_status_code: 301 + paths: + - /r1 \ No newline at end of file diff --git a/tests/integration/testdata/validate/konnect_1_1.yaml b/tests/integration/testdata/validate/konnect_1_1.yaml new file mode 100644 index 000000000..839c993db --- /dev/null +++ b/tests/integration/testdata/validate/konnect_1_1.yaml @@ -0,0 +1,18 @@ +_format_version: "1.1" +_konnect: + control_plane_name: default +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - name: r1 + id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + https_redirect_status_code: 301 + paths: + - /r1 \ No newline at end of file diff --git a/tests/integration/testdata/validate/konnect_invalid.yaml b/tests/integration/testdata/validate/konnect_invalid.yaml new file mode 100644 index 000000000..ec07c8c57 --- /dev/null +++ b/tests/integration/testdata/validate/konnect_invalid.yaml @@ -0,0 +1,16 @@ +_format_version: "3.0" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - name: r1 + id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + https_redirect_status_code: 301 + paths: + - /r1 \ No newline at end of file diff --git a/tests/integration/testdata/validate/konnect_no_version.yaml b/tests/integration/testdata/validate/konnect_no_version.yaml new file mode 100644 index 000000000..89a2b6bc9 --- /dev/null +++ b/tests/integration/testdata/validate/konnect_no_version.yaml @@ -0,0 +1,17 @@ +_konnect: + control_plane_name: default +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - name: r1 + id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + https_redirect_status_code: 301 + paths: + - /r1 \ No newline at end of file diff --git a/tests/integration/testdata/validate/rbac-resources.yaml b/tests/integration/testdata/validate/rbac-resources.yaml new file mode 100644 index 000000000..06ab6e792 --- /dev/null +++ b/tests/integration/testdata/validate/rbac-resources.yaml @@ -0,0 +1,93 @@ +_format_version: "3.0" +_konnect: + control_plane_name: default +rbac_roles: +- comment: Full access to Dev Portal related endpoints in the workspace + endpoint_permissions: + - actions: + - read + - delete + - create + - update + endpoint: /developers + negative: false + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /developers/* + negative: false + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /files + negative: false + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /files/* + negative: false + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /kong + negative: false + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /rbac/* + negative: true + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /rbac/*/* + negative: true + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /rbac/*/*/* + negative: true + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /rbac/*/*/*/* + negative: true + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /rbac/*/*/*/*/* + negative: true + workspace: default + - actions: + - read + - update + endpoint: /workspaces/default + negative: false + workspace: default + name: workspace-portal-admin diff --git a/tests/integration/validate_test.go b/tests/integration/validate_test.go new file mode 100644 index 000000000..958519e8f --- /dev/null +++ b/tests/integration/validate_test.go @@ -0,0 +1,95 @@ +//go:build integration + +package integration + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +const ( + ONLINE = true + OFFLINE = false +) + +func Test_Validate_Konnect(t *testing.T) { + setup(t) + runWhen(t, "konnect", "") + + tests := []struct { + name string + stateFile string + additionalArgs []string + errorExpected bool + errorString string + }{ + { + name: "validate with konnect", + stateFile: "testdata/validate/konnect.yaml", + additionalArgs: []string{}, + errorExpected: false, + }, + { + name: "validate with --konnect-compatibility", + stateFile: "testdata/validate/konnect.yaml", + additionalArgs: []string{"--konnect-compatibility"}, + errorExpected: false, + }, + { + name: "validate with 1.1 version file", + stateFile: "testdata/validate/konnect_1_1.yaml", + additionalArgs: []string{}, + errorExpected: true, + errorString: "[version] decK file version must be '3.0' or greater", + }, + { + name: "validate with no version in deck file", + stateFile: "testdata/validate/konnect_no_version.yaml", + additionalArgs: []string{}, + errorExpected: true, + errorString: "[version] unable to determine decK file version", + }, + { + name: "validate with --rbac-resources-only", + stateFile: "testdata/validate/rbac-resources.yaml", + additionalArgs: []string{"--rbac-resources-only"}, + errorExpected: true, + errorString: "[rbac] not yet supported by konnect", + }, + { + name: "validate with workspace set", + stateFile: "testdata/validate/konnect.yaml", + additionalArgs: []string{"--workspace=default"}, + errorExpected: true, + errorString: "[workspaces] not supported by Konnect - use control planes instead", + }, + { + name: "validate with no konnect config in file", + stateFile: "testdata/validate/konnect_invalid.yaml", + additionalArgs: []string{}, + errorExpected: true, + errorString: "[konnect] section not specified - ensure details are set via cli flags", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + validateOpts := append([]string{ + tc.stateFile, + }, tc.additionalArgs...) + + err := validate(ONLINE, validateOpts...) + + if tc.errorExpected { + assert.Error(t, err) + if tc.errorString != "" { + assert.Contains(t, err.Error(), tc.errorString) + } + return + } + + assert.NoError(t, err) + }) + } +} From ffde1fa932dfbd5da2f70ba6a6150033974894f0 Mon Sep 17 00:00:00 2001 From: Prashansa Kulshrestha Date: Mon, 21 Oct 2024 20:12:07 +0530 Subject: [PATCH 5/7] tests: added tests for deck file and gateway validate (#1415) * feat: support online validation with Konnect * tests: Added e2e tests for gateway validation with konnect. Also, this change adds a conditional that ensures that rbac flag used with konnect mode, gives an legible error to the user. * chore: lint fix * chore: removed workspace flag test as it is not supported with konnect * tests: added rbac-resources file * refactor: refactored tests and code to add all konnect validate usecases * chore: fixed workspace setting for Konnect check * chore: added mutually exclusive flags for konnect compatibility * chore: fixed logical error * chore: fixed descripancy in info due to preRun order in cobra * chore: added corrections based on PR review * removing unrelated code for vault validation * tests: added tests for deck file and gateway validate * tests: added tests with consumers and creds --------- Co-authored-by: Gabriele Gerbino --- .../testdata/validate/kong-ee.yaml | 32 +++++ tests/integration/testdata/validate/kong.yaml | 16 +++ .../integration/testdata/validate/kong3x.yaml | 16 +++ tests/integration/validate_test.go | 135 ++++++++++++++++++ 4 files changed, 199 insertions(+) create mode 100644 tests/integration/testdata/validate/kong-ee.yaml create mode 100644 tests/integration/testdata/validate/kong.yaml create mode 100644 tests/integration/testdata/validate/kong3x.yaml diff --git a/tests/integration/testdata/validate/kong-ee.yaml b/tests/integration/testdata/validate/kong-ee.yaml new file mode 100644 index 000000000..460a25741 --- /dev/null +++ b/tests/integration/testdata/validate/kong-ee.yaml @@ -0,0 +1,32 @@ +_format_version: "3.0" +services: + - name: example-service + url: http://mockbin.org + routes: + - name: example-route + paths: + - /mock + methods: + - GET + - POST + strip_path: false + preserve_host: true + plugins: + - name: rate-limiting + config: + minute: 5 + policy: local +consumers: + - keyauth_credentials: + - key: alice-secret-key + username: alice + - keyauth_credentials: + - key: bob-secret-key + username: bob +plugins: + - name: key-auth + config: + key_names: + - apikey + hide_credentials: true + run_on_preflight: true diff --git a/tests/integration/testdata/validate/kong.yaml b/tests/integration/testdata/validate/kong.yaml new file mode 100644 index 000000000..da79fdfed --- /dev/null +++ b/tests/integration/testdata/validate/kong.yaml @@ -0,0 +1,16 @@ +_format_version: "1.1" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - name: r1 + id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + https_redirect_status_code: 301 + paths: + - /r1 \ No newline at end of file diff --git a/tests/integration/testdata/validate/kong3x.yaml b/tests/integration/testdata/validate/kong3x.yaml new file mode 100644 index 000000000..a6ff52d42 --- /dev/null +++ b/tests/integration/testdata/validate/kong3x.yaml @@ -0,0 +1,16 @@ +_format_version: "3.0" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - name: r1 + id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + https_redirect_status_code: 301 + paths: + - /r1 diff --git a/tests/integration/validate_test.go b/tests/integration/validate_test.go index 958519e8f..a766b6d21 100644 --- a/tests/integration/validate_test.go +++ b/tests/integration/validate_test.go @@ -93,3 +93,138 @@ func Test_Validate_Konnect(t *testing.T) { }) } } + +func Test_Validate_File(t *testing.T) { + setup(t) + + tests := []struct { + name string + stateFile string + additionalArgs []string + errorExpected bool + }{ + { + name: "file validate format version 1.1", + stateFile: "testdata/validate/kong.yaml", + additionalArgs: []string{}, + }, + { + name: "file validate format version 3.0", + stateFile: "testdata/validate/kong3x.yaml", + additionalArgs: []string{}, + }, + { + name: "file validate with --konnect-compatibility", + stateFile: "testdata/validate/konnect.yaml", + additionalArgs: []string{"--konnect-compatibility"}, + }, + { + name: "file validate with --workspace", + stateFile: "testdata/validate/kong3x.yaml", + additionalArgs: []string{"--workspace=default"}, + }, + { + name: "file validate with --rbac-resources-only", + stateFile: "testdata/validate/rbac-resources.yaml", + additionalArgs: []string{"--rbac-resources-only"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + validateOpts := []string{ + tc.stateFile, + } + validateOpts = append(validateOpts, tc.additionalArgs...) + + err := validate(OFFLINE, validateOpts...) + assert.NoError(t, err) + }) + } +} + +func Test_Validate_Gateway(t *testing.T) { + setup(t) + runWhen(t, "kong", ">=2.8.0") + + tests := []struct { + name string + stateFile string + additionalArgs []string + errorExpected bool + }{ + { + name: "validate format version 1.1", + stateFile: "testdata/validate/kong.yaml", + additionalArgs: []string{}, + }, + { + name: "validate format version 3.0", + stateFile: "testdata/validate/kong3x.yaml", + additionalArgs: []string{}, + }, + { + name: "validate with --konnect-compatibility", + stateFile: "testdata/validate/konnect.yaml", + additionalArgs: []string{"--konnect-compatibility"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + validateOpts := []string{ + tc.stateFile, + } + validateOpts = append(validateOpts, tc.additionalArgs...) + + err := validate(ONLINE, validateOpts...) + assert.NoError(t, err) + }) + } +} + +func Test_Validate_Gateway_EE(t *testing.T) { + setup(t) + runWhen(t, "enterprise", ">=2.8.0") + + tests := []struct { + name string + stateFile string + additionalArgs []string + errorExpected bool + }{ + { + name: "validate format version 1.1", + stateFile: "testdata/validate/kong.yaml", + additionalArgs: []string{}, + }, + { + name: "validate format version 3.0", + stateFile: "testdata/validate/kong-ee.yaml", + additionalArgs: []string{}, + }, + { + name: "validate with --konnect-compatibility", + stateFile: "testdata/validate/konnect.yaml", + additionalArgs: []string{"--konnect-compatibility"}, + }, + { + name: "validate with --workspace", + stateFile: "testdata/validate/kong-ee.yaml", + additionalArgs: []string{"--workspace=default"}, + }, + // TODO: Add a rbac flag test, once the behaviour is fixed + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + validateOpts := []string{ + tc.stateFile, + } + validateOpts = append(validateOpts, tc.additionalArgs...) + + err := validate(ONLINE, validateOpts...) + assert.NoError(t, err) + }) + } +} From da3d70e657b108b9bddd0f7f3e41011a39ad2dd3 Mon Sep 17 00:00:00 2001 From: Prashansa Kulshrestha Date: Mon, 21 Oct 2024 20:29:34 +0530 Subject: [PATCH 6/7] chore: release prep for v1.41.0 (#1423) * chore: release prep for v1.41.0 * removed extra newlines --- CHANGELOG.md | 14 ++++++++++++++ README.md | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0727db81e..eeab8414b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Table of Contents +- [v1.41.0](#v1410) - [v1.40.3](#v1403) - [v1.40.2](#v1402) - [v1.40.1](#v1401) @@ -96,6 +97,18 @@ - [v0.2.0](#v020) - [v0.1.0](#v010) +## [v1.41.0] +> Release date: 2024/10/21 + +### Added +- `deck gateway validate` command now supports Konnect. Konnect entities can be validated online with this change. +[#1335](https://github.com/Kong/deck/pull/1335) + +### Fixes +- Quoted type constraints are removed for Terraform. Type constraints in quotes were required in Terraform <= 0.11, +It is now deprecated and will be removed in a future Terraform versions. Thus, removed them from kong2tf generation, so as +to avoid potential errors in `terraform apply`. [#1412](https://github.com/Kong/deck/pull/1412) + ## [v1.40.3] > Release date: 2024/09/26 @@ -1822,6 +1835,7 @@ No breaking changes have been introduced in this release. Debut release of decK +[v1.41.0]: https://github.com/Kong/deck/compare/v1.40.3...v1.41.0 [v1.40.3]: https://github.com/Kong/deck/compare/v1.40.2...v1.40.3 [v1.40.2]: https://github.com/Kong/deck/compare/v1.40.1...v1.40.2 [v1.40.1]: https://github.com/Kong/deck/compare/v1.40.0...v1.40.1 diff --git a/README.md b/README.md index d3ea79ec0..e79f2e1b4 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ the GitHub [release page](https://github.com/kong/deck/releases) or install by downloading the binary: ```shell -$ curl -sL https://github.com/kong/deck/releases/download/v1.40.3/deck_1.40.3_linux_amd64.tar.gz -o deck.tar.gz +$ curl -sL https://github.com/kong/deck/releases/download/v1.41.0/deck_1.41.0_linux_amd64.tar.gz -o deck.tar.gz $ tar -xf deck.tar.gz -C /tmp $ sudo cp /tmp/deck /usr/local/bin/ ``` @@ -84,7 +84,7 @@ If you are on Windows, you can download the binary from the GitHub [release page](https://github.com/kong/deck/releases) or via PowerShell: ```shell -$ curl -sL https://github.com/kong/deck/releases/download/v1.40.3/deck_1.40.3_windows_amd64.tar.gz -o deck.tar.gz +$ curl -sL https://github.com/kong/deck/releases/download/v1.41.0/deck_1.41.0_windows_amd64.tar.gz -o deck.tar.gz $ tar -xzvf deck.tar.gz ``` From 947e3497346ae72ade68a509257c787b5e89e6de Mon Sep 17 00:00:00 2001 From: Prashansa Kulshrestha Date: Tue, 22 Oct 2024 12:49:33 +0530 Subject: [PATCH 7/7] fix: konnect cli flags getting considered for online validation. (#1424) * fix: konnect cli flags getting considered for online validation. Earlier, if konnect control plane information was passed via cli flags, online validation for Konnect was failing. This change fixes the issue. * chore: added changelog for v1.41.1 --- CHANGELOG.md | 9 +++++++++ README.md | 4 ++-- cmd/gateway_validate.go | 2 +- tests/integration/validate_test.go | 13 +++++++++---- validate/konnect_compatibility.go | 5 +++-- validate/konnect_compatibility_test.go | 25 +++++++++++++++++++++---- 6 files changed, 45 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eeab8414b..b626c09d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Table of Contents +- [v1.41.1](#v1411) - [v1.41.0](#v1410) - [v1.40.3](#v1403) - [v1.40.2](#v1402) @@ -97,6 +98,13 @@ - [v0.2.0](#v020) - [v0.1.0](#v010) +## [v1.41.1] +> Release date: 2024/10/22 + +### Fixes +- `deck gateway validate` for Konnect supports Konnect configs passed by CLI flags now. +Earlier, the validation was failing if control plane information was passed via CLI flags. + ## [v1.41.0] > Release date: 2024/10/21 @@ -1835,6 +1843,7 @@ No breaking changes have been introduced in this release. Debut release of decK +[v1.41.1]: https://github.com/Kong/deck/compare/v1.40.0...v1.41.1 [v1.41.0]: https://github.com/Kong/deck/compare/v1.40.3...v1.41.0 [v1.40.3]: https://github.com/Kong/deck/compare/v1.40.2...v1.40.3 [v1.40.2]: https://github.com/Kong/deck/compare/v1.40.1...v1.40.2 diff --git a/README.md b/README.md index e79f2e1b4..cd9bcc971 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ the GitHub [release page](https://github.com/kong/deck/releases) or install by downloading the binary: ```shell -$ curl -sL https://github.com/kong/deck/releases/download/v1.41.0/deck_1.41.0_linux_amd64.tar.gz -o deck.tar.gz +$ curl -sL https://github.com/kong/deck/releases/download/v1.41.1/deck_1.41.1_linux_amd64.tar.gz -o deck.tar.gz $ tar -xf deck.tar.gz -C /tmp $ sudo cp /tmp/deck /usr/local/bin/ ``` @@ -84,7 +84,7 @@ If you are on Windows, you can download the binary from the GitHub [release page](https://github.com/kong/deck/releases) or via PowerShell: ```shell -$ curl -sL https://github.com/kong/deck/releases/download/v1.41.0/deck_1.41.0_windows_amd64.tar.gz -o deck.tar.gz +$ curl -sL https://github.com/kong/deck/releases/download/v1.41.1/deck_1.41.1_windows_amd64.tar.gz -o deck.tar.gz $ tar -xzvf deck.tar.gz ``` diff --git a/cmd/gateway_validate.go b/cmd/gateway_validate.go index 455cec32a..0d2ee3690 100644 --- a/cmd/gateway_validate.go +++ b/cmd/gateway_validate.go @@ -141,7 +141,7 @@ func executeValidate(cmd *cobra.Command, _ []string) error { } if validateKonnectCompatibility || (mode == modeKonnect && validateOnline) { - if errs := validate.KonnectCompatibility(targetContent); len(errs) != 0 { + if errs := validate.KonnectCompatibility(targetContent, dumpConfig); len(errs) != 0 { return validate.ErrorsWrapper{Errors: errs} } diff --git a/tests/integration/validate_test.go b/tests/integration/validate_test.go index a766b6d21..410bce2ef 100644 --- a/tests/integration/validate_test.go +++ b/tests/integration/validate_test.go @@ -65,11 +65,16 @@ func Test_Validate_Konnect(t *testing.T) { errorString: "[workspaces] not supported by Konnect - use control planes instead", }, { - name: "validate with no konnect config in file", + name: "validate with no konnect config in file, passed via cli flag konnect control plane", stateFile: "testdata/validate/konnect_invalid.yaml", - additionalArgs: []string{}, - errorExpected: true, - errorString: "[konnect] section not specified - ensure details are set via cli flags", + additionalArgs: []string{"--konnect-control-plane-name=default"}, + errorExpected: false, + }, + { + name: "validate with no konnect config in file, passed via cli flag konnect runtime group", + stateFile: "testdata/validate/konnect_invalid.yaml", + additionalArgs: []string{"--konnect-runtime-group-name=default"}, + errorExpected: false, }, } diff --git a/validate/konnect_compatibility.go b/validate/konnect_compatibility.go index 74eb617b7..663ed71d0 100644 --- a/validate/konnect_compatibility.go +++ b/validate/konnect_compatibility.go @@ -5,6 +5,7 @@ import ( "fmt" "strconv" + "github.com/kong/go-database-reconciler/pkg/dump" "github.com/kong/go-database-reconciler/pkg/file" "github.com/kong/go-kong/kong" ) @@ -39,14 +40,14 @@ func checkPlugin(name *string, config kong.Configuration) error { return nil } -func KonnectCompatibility(targetContent *file.Content) []error { +func KonnectCompatibility(targetContent *file.Content, dumpConfig dump.Config) []error { var errs []error if targetContent.Workspace != "" { errs = append(errs, errors.New(errWorkspace)) } - if targetContent.Konnect == nil { + if targetContent.Konnect == nil && dumpConfig.KonnectControlPlane == "" { errs = append(errs, errors.New(errKonnect)) } diff --git a/validate/konnect_compatibility_test.go b/validate/konnect_compatibility_test.go index d4a120580..41a9d9da7 100644 --- a/validate/konnect_compatibility_test.go +++ b/validate/konnect_compatibility_test.go @@ -5,6 +5,7 @@ import ( "fmt" "testing" + "github.com/kong/go-database-reconciler/pkg/dump" "github.com/kong/go-database-reconciler/pkg/file" "github.com/kong/go-kong/kong" "github.com/stretchr/testify/assert" @@ -12,9 +13,10 @@ import ( func Test_KonnectCompatibility(t *testing.T) { tests := []struct { - name string - content *file.Content - expected []error + name string + content *file.Content + dumpConfig dump.Config + expected []error }{ { name: "version invalid", @@ -26,6 +28,7 @@ func Test_KonnectCompatibility(t *testing.T) { ControlPlaneName: "s", }, }, + dumpConfig: dump.Config{}, expected: []error{ errors.New(errWorkspace), errors.New(errBadVersion), @@ -36,6 +39,7 @@ func Test_KonnectCompatibility(t *testing.T) { content: &file.Content{ FormatVersion: "3.1", }, + dumpConfig: dump.Config{}, expected: []error{ errors.New(errKonnect), }, @@ -60,6 +64,7 @@ func Test_KonnectCompatibility(t *testing.T) { }}, }, }, + dumpConfig: dump.Config{}, expected: []error{ fmt.Errorf(errPluginIncompatible, "oauth2"), }, @@ -95,6 +100,7 @@ func Test_KonnectCompatibility(t *testing.T) { }}, }, }, + dumpConfig: dump.Config{}, expected: []error{ fmt.Errorf(errPluginIncompatible, "oauth2"), fmt.Errorf("[%s] keys are automatically encrypted in Konnect, use the key auth plugin instead", "key-auth-enc"), @@ -128,15 +134,26 @@ func Test_KonnectCompatibility(t *testing.T) { }, }, }, + dumpConfig: dump.Config{}, expected: []error{ fmt.Errorf(errPluginNoCluster, "response-ratelimiting"), fmt.Errorf("[%s] keys are automatically encrypted in Konnect, use the key auth plugin instead", "key-auth-enc"), }, }, + { + name: "no konnect info in file, but passed via cli flag", + content: &file.Content{ + FormatVersion: "3.1", + }, + dumpConfig: dump.Config{ + KonnectControlPlane: "default", + }, + expected: nil, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - errs := KonnectCompatibility(tt.content) + errs := KonnectCompatibility(tt.content, tt.dumpConfig) assert.Equal(t, tt.expected, errs) }) }