From ef456f640e5ff757642c7945867c1464f39edff4 Mon Sep 17 00:00:00 2001 From: Eguzki Astiz Lezaun Date: Wed, 15 May 2024 18:37:52 +0200 Subject: [PATCH] [BREAKING CHANGE] root level kuadrant extensions --- cmd/generate_gatewayapi_httproute_test.go | 141 ++++++++++++++++++ cmd/generate_kuadrant_authpolicy_test.go | 111 ++++++++++++++ cmd/generate_kuadrant_ratelimitpolicy_test.go | 117 +++++++++++++++ cmd/testdata/petstore_openapi.yaml | 77 ++++++++++ doc/generate-kuadrant-auth-policy.md | 18 +-- doc/generate-kuadrant-rate-limit-policy.md | 18 +-- doc/openapi-apicurio.md | 25 ++-- doc/openapi-kuadrant-extensions.md | 27 ++-- doc/openapi-openshift-dev-spaces.md | 29 ++-- .../petstore-multiple-sec-requirements.yaml | 18 +-- ...etstore-with-oidc-kuadrant-extensions.yaml | 18 +-- ...e-with-rate-limit-kuadrant-extensions.yaml | 18 +-- pkg/gatewayapi/http_route.go | 53 +++---- pkg/utils/kuadrant_oas_extension_types.go | 15 +- 14 files changed, 559 insertions(+), 126 deletions(-) create mode 100644 cmd/generate_gatewayapi_httproute_test.go create mode 100644 cmd/generate_kuadrant_authpolicy_test.go create mode 100644 cmd/generate_kuadrant_ratelimitpolicy_test.go create mode 100644 cmd/testdata/petstore_openapi.yaml diff --git a/cmd/generate_gatewayapi_httproute_test.go b/cmd/generate_gatewayapi_httproute_test.go new file mode 100644 index 0000000..32cecfe --- /dev/null +++ b/cmd/generate_gatewayapi_httproute_test.go @@ -0,0 +1,141 @@ +package cmd + +import ( + "bytes" + "io/ioutil" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" + "sigs.k8s.io/yaml" +) + +var _ = Describe("Generate HTTPRoute", func() { + var ( + cmd *cobra.Command + cmdStdoutBuffer *bytes.Buffer + cmdStderrBuffer *bytes.Buffer + ) + + BeforeEach(func() { + cmd = generateGatewayApiHttpRouteCommand() + cmdStdoutBuffer = bytes.NewBufferString("") + cmdStderrBuffer = bytes.NewBufferString("") + cmd.SetOut(cmdStdoutBuffer) + cmd.SetErr(cmdStderrBuffer) + }) + + Context("with invalid OAS", func() { + It("happy path", func() { + cmd.SetArgs([]string{"--oas", "testdata/invalid_oas.yaml"}) + Expect(cmd.Execute()).Should(MatchError(ContainSubstring("OpenAPI validation error"))) + + }) + }) + + Context("with root level kuadrant extensions", func() { + It("HTTPRoute is generated", func() { + cmd.SetArgs([]string{"--oas", "testdata/petstore_openapi.yaml"}) + Expect(cmd.Execute()).ShouldNot(HaveOccurred()) + out, err := ioutil.ReadAll(cmdStdoutBuffer) + Expect(err).ShouldNot(HaveOccurred()) + + var httpRoute gatewayapiv1.HTTPRoute + Expect(yaml.Unmarshal(out, &httpRoute)).ShouldNot(HaveOccurred()) + Expect(httpRoute.TypeMeta).To(Equal(metav1.TypeMeta{ + APIVersion: gatewayapiv1.GroupVersion.String(), + Kind: "HTTPRoute", + })) + Expect(httpRoute.ObjectMeta).To(Equal(metav1.ObjectMeta{ + Name: "petstore", + Namespace: "petstore-ns", + })) + Expect(httpRoute.Spec.CommonRouteSpec).To(Equal(gatewayapiv1.CommonRouteSpec{ + ParentRefs: []gatewayapiv1.ParentReference{ + { + Name: "gw", Namespace: ptr.To(gatewayapiv1.Namespace("gw-ns")), + }, + }, + })) + Expect(httpRoute.Spec.Hostnames).To(Equal([]gatewayapiv1.Hostname{ + gatewayapiv1.Hostname("example.com"), + })) + Expect(httpRoute.Spec.Rules).To(HaveLen(3)) + Expect(httpRoute.Spec.Rules).To(ContainElement( + gatewayapiv1.HTTPRouteRule{ + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: ptr.To(gatewayapiv1.PathMatchExact), + Value: ptr.To("/v1/cat"), + }, + Method: ptr.To(gatewayapiv1.HTTPMethodGet), + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Name: "petstore", + Namespace: ptr.To(gatewayapiv1.Namespace("petstore")), + Port: ptr.To(gatewayapiv1.PortNumber(80)), + }, + }, + }, + }, + }, + )) + Expect(httpRoute.Spec.Rules).To(ContainElement( + gatewayapiv1.HTTPRouteRule{ + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: ptr.To(gatewayapiv1.PathMatchExact), + Value: ptr.To("/v1/dog"), + }, + Method: ptr.To(gatewayapiv1.HTTPMethodGet), + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Name: "petstore", + Namespace: ptr.To(gatewayapiv1.Namespace("petstore")), + Port: ptr.To(gatewayapiv1.PortNumber(80)), + }, + }, + }, + }, + }, + )) + Expect(httpRoute.Spec.Rules).To(ContainElement( + gatewayapiv1.HTTPRouteRule{ + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: ptr.To(gatewayapiv1.PathMatchExact), + Value: ptr.To("/v1/dog"), + }, + Method: ptr.To(gatewayapiv1.HTTPMethodPost), + }, + }, + BackendRefs: []gatewayapiv1.HTTPBackendRef{ + { + BackendRef: gatewayapiv1.BackendRef{ + BackendObjectReference: gatewayapiv1.BackendObjectReference{ + Name: "petstore", + Namespace: ptr.To(gatewayapiv1.Namespace("petstore")), + Port: ptr.To(gatewayapiv1.PortNumber(80)), + }, + }, + }, + }, + }, + )) + }) + }) +}) diff --git a/cmd/generate_kuadrant_authpolicy_test.go b/cmd/generate_kuadrant_authpolicy_test.go new file mode 100644 index 0000000..ea89de9 --- /dev/null +++ b/cmd/generate_kuadrant_authpolicy_test.go @@ -0,0 +1,111 @@ +package cmd + +import ( + "bytes" + "io/ioutil" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" + gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + "sigs.k8s.io/yaml" + + authorinoapi "github.com/kuadrant/authorino/api/v1beta2" + kuadrantapiv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" +) + +var _ = Describe("Generate AuthPolicy", func() { + var ( + cmd *cobra.Command + cmdStdoutBuffer *bytes.Buffer + cmdStderrBuffer *bytes.Buffer + ) + + BeforeEach(func() { + cmd = generateKuadrantAuthPolicyCommand() + cmdStdoutBuffer = bytes.NewBufferString("") + cmdStderrBuffer = bytes.NewBufferString("") + cmd.SetOut(cmdStdoutBuffer) + cmd.SetErr(cmdStderrBuffer) + }) + + Context("with invalid OAS", func() { + It("happy path", func() { + cmd.SetArgs([]string{"--oas", "testdata/invalid_oas.yaml"}) + Expect(cmd.Execute()).Should(MatchError(ContainSubstring("OpenAPI validation error"))) + + }) + }) + + Context("with operation including security", func() { + It("authorization policy generated", func() { + cmd.SetArgs([]string{"--oas", "testdata/petstore_openapi.yaml"}) + Expect(cmd.Execute()).ShouldNot(HaveOccurred()) + out, err := ioutil.ReadAll(cmdStdoutBuffer) + Expect(err).ShouldNot(HaveOccurred()) + + var kap kuadrantapiv1beta2.AuthPolicy + Expect(yaml.Unmarshal(out, &kap)).ShouldNot(HaveOccurred()) + Expect(kap.TypeMeta).To(Equal(metav1.TypeMeta{ + APIVersion: kuadrantapiv1beta2.GroupVersion.String(), Kind: "AuthPolicy", + })) + Expect(kap.ObjectMeta).To(Equal(metav1.ObjectMeta{ + Name: "petstore", + Namespace: "petstore-ns", + })) + Expect(kap.Spec.TargetRef).To(Equal(gatewayapiv1alpha2.PolicyTargetReference{ + Group: gatewayapiv1.GroupName, + Kind: gatewayapiv1.Kind("HTTPRoute"), + Name: gatewayapiv1.ObjectName("petstore"), + Namespace: ptr.To(gatewayapiv1.Namespace("petstore-ns")), + })) + Expect(kap.Spec.AuthPolicyCommonSpec.RouteSelectors).To(HaveExactElements( + kuadrantapiv1beta2.RouteSelector{ + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: ptr.To(gatewayapiv1.PathMatchExact), + Value: ptr.To("/v1/dog"), + }, + Method: ptr.To(gatewayapiv1.HTTPMethodPost), + }, + }, + }, + )) + Expect(kap.Spec.AuthPolicyCommonSpec.AuthScheme).To(Equal( + &kuadrantapiv1beta2.AuthSchemeSpec{ + Authentication: map[string]kuadrantapiv1beta2.AuthenticationSpec{ + "postDog_securedDog": kuadrantapiv1beta2.AuthenticationSpec{ + AuthenticationSpec: authorinoapi.AuthenticationSpec{ + Credentials: authorinoapi.Credentials{}, + AuthenticationMethodSpec: authorinoapi.AuthenticationMethodSpec{ + Jwt: &authorinoapi.JwtAuthenticationSpec{ + IssuerUrl: "https://example.com/.well-known/openid-configuration", + }, + }, + }, + CommonAuthRuleSpec: kuadrantapiv1beta2.CommonAuthRuleSpec{ + RouteSelectors: []kuadrantapiv1beta2.RouteSelector{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: ptr.To(gatewayapiv1.PathMatchExact), + Value: ptr.To("/v1/dog"), + }, + Method: ptr.To(gatewayapiv1.HTTPMethodPost), + }, + }, + }, + }, + }, + }, + }, + }, + )) + }) + }) +}) diff --git a/cmd/generate_kuadrant_ratelimitpolicy_test.go b/cmd/generate_kuadrant_ratelimitpolicy_test.go new file mode 100644 index 0000000..1441d08 --- /dev/null +++ b/cmd/generate_kuadrant_ratelimitpolicy_test.go @@ -0,0 +1,117 @@ +package cmd + +import ( + "bytes" + "io/ioutil" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" + gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + "sigs.k8s.io/yaml" + + kuadrantapiv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" +) + +var _ = Describe("Generate Ratelimitpolicy", func() { + var ( + cmd *cobra.Command + cmdStdoutBuffer *bytes.Buffer + cmdStderrBuffer *bytes.Buffer + ) + + BeforeEach(func() { + cmd = generateKuadrantRateLimitPolicyCommand() + cmdStdoutBuffer = bytes.NewBufferString("") + cmdStderrBuffer = bytes.NewBufferString("") + cmd.SetOut(cmdStdoutBuffer) + cmd.SetErr(cmdStderrBuffer) + }) + + Context("with invalid OAS", func() { + It("happy path", func() { + cmd.SetArgs([]string{"--oas", "testdata/invalid_oas.yaml"}) + Expect(cmd.Execute()).Should(MatchError(ContainSubstring("OpenAPI validation error"))) + + }) + }) + + Context("with rate limiting kuadrant extensions", func() { + It("rate limit policy generated", func() { + cmd.SetArgs([]string{"--oas", "testdata/petstore_openapi.yaml"}) + Expect(cmd.Execute()).ShouldNot(HaveOccurred()) + out, err := ioutil.ReadAll(cmdStdoutBuffer) + Expect(err).ShouldNot(HaveOccurred()) + + var rlp kuadrantapiv1beta2.RateLimitPolicy + Expect(yaml.Unmarshal(out, &rlp)).ShouldNot(HaveOccurred()) + Expect(rlp.TypeMeta).To(Equal(metav1.TypeMeta{ + APIVersion: kuadrantapiv1beta2.GroupVersion.String(), Kind: "RateLimitPolicy", + })) + Expect(rlp.ObjectMeta).To(Equal(metav1.ObjectMeta{ + Name: "petstore", + Namespace: "petstore-ns", + })) + Expect(rlp.Spec.TargetRef).To(Equal(gatewayapiv1alpha2.PolicyTargetReference{ + Group: gatewayapiv1.GroupName, + Kind: gatewayapiv1.Kind("HTTPRoute"), + Name: gatewayapiv1.ObjectName("petstore"), + Namespace: ptr.To(gatewayapiv1.Namespace("petstore-ns")), + })) + Expect(rlp.Spec.RateLimitPolicyCommonSpec.Limits).To(HaveLen(2)) + Expect(rlp.Spec.RateLimitPolicyCommonSpec.Limits).To(HaveKeyWithValue("getCat", kuadrantapiv1beta2.Limit{ + Counters: []kuadrantapiv1beta2.ContextSelector{ + "request.headers.x-forwarded-for", + }, + RouteSelectors: []kuadrantapiv1beta2.RouteSelector{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: ptr.To(gatewayapiv1.PathMatchExact), + Value: ptr.To("/v1/cat"), + }, + Method: ptr.To(gatewayapiv1.HTTPMethodGet), + }, + }, + }, + }, + Rates: []kuadrantapiv1beta2.Rate{ + { + Limit: 1, + Duration: 10, + Unit: kuadrantapiv1beta2.TimeUnit("second"), + }, + }, + })) + Expect(rlp.Spec.RateLimitPolicyCommonSpec.Limits).To(HaveKeyWithValue("getDog", kuadrantapiv1beta2.Limit{ + Counters: []kuadrantapiv1beta2.ContextSelector{ + "request.headers.x-forwarded-for", + }, + RouteSelectors: []kuadrantapiv1beta2.RouteSelector{ + { + Matches: []gatewayapiv1.HTTPRouteMatch{ + { + Path: &gatewayapiv1.HTTPPathMatch{ + Type: ptr.To(gatewayapiv1.PathMatchExact), + Value: ptr.To("/v1/dog"), + }, + Method: ptr.To(gatewayapiv1.HTTPMethodGet), + }, + }, + }, + }, + Rates: []kuadrantapiv1beta2.Rate{ + { + Limit: 3, + Duration: 10, + Unit: kuadrantapiv1beta2.TimeUnit("second"), + }, + }, + })) + }) + }) +}) diff --git a/cmd/testdata/petstore_openapi.yaml b/cmd/testdata/petstore_openapi.yaml new file mode 100644 index 0000000..232966b --- /dev/null +++ b/cmd/testdata/petstore_openapi.yaml @@ -0,0 +1,77 @@ +--- +openapi: "3.0.3" +info: + title: "Pet Store API" + version: "1.0.0" +x-kuadrant: + route: + name: "petstore" + namespace: "petstore-ns" + hostnames: + - example.com + parentRefs: + - name: gw + namespace: gw-ns +servers: + - url: https://example.io/v1 +paths: + /cat: + x-kuadrant: ## Path level Kuadrant Extension + backendRefs: + - name: petstore + port: 80 + namespace: petstore + rate_limit: + rates: + - limit: 1 + duration: 10 + unit: second + counters: + - request.headers.x-forwarded-for + get: # Added to the route and rate limited + operationId: "getCat" + responses: + 405: + description: "invalid input" + post: # NOT added to the route + x-kuadrant: + disable: true + operationId: "postCat" + responses: + 405: + description: "invalid input" + /dog: + get: # Added to the route and rate limited + x-kuadrant: ## Operation level Kuadrant Extension + backendRefs: + - name: petstore + port: 80 + namespace: petstore + rate_limit: + rates: + - limit: 3 + duration: 10 + unit: second + counters: + - request.headers.x-forwarded-for + operationId: "getDog" + responses: + 405: + description: "invalid input" + post: # Added to the route, NOT rate limited, secured + x-kuadrant: ## Operation level Kuadrant Extension + backendRefs: + - name: petstore + port: 80 + namespace: petstore + operationId: "postDog" + security: + - securedDog: [] + responses: + 405: + description: "invalid input" +components: + securitySchemes: + securedDog: + type: openIdConnect + openIdConnectUrl: https://example.com/.well-known/openid-configuration diff --git a/doc/generate-kuadrant-auth-policy.md b/doc/generate-kuadrant-auth-policy.md index 22fe43d..4462700 100644 --- a/doc/generate-kuadrant-auth-policy.md +++ b/doc/generate-kuadrant-auth-policy.md @@ -239,15 +239,15 @@ openapi: "3.1.0" info: title: "Pet Store API" version: "1.0.0" - x-kuadrant: - route: - name: "petstore" - namespace: "petstore" - hostnames: - - example.com - parentRefs: - - name: istio-ingressgateway - namespace: istio-system +x-kuadrant: + route: + name: "petstore" + namespace: "petstore" + hostnames: + - example.com + parentRefs: + - name: istio-ingressgateway + namespace: istio-system servers: - url: https://example.io/api/v1 paths: diff --git a/doc/generate-kuadrant-rate-limit-policy.md b/doc/generate-kuadrant-rate-limit-policy.md index f95c820..646f7d2 100644 --- a/doc/generate-kuadrant-rate-limit-policy.md +++ b/doc/generate-kuadrant-rate-limit-policy.md @@ -62,15 +62,15 @@ openapi: "3.0.3" info: title: "Pet Store API" version: "1.0.0" - x-kuadrant: - route: - name: "petstore" - namespace: "petstore" - hostnames: - - example.com - parentRefs: - - name: istio-ingressgateway - namespace: istio-system +x-kuadrant: + route: + name: "petstore" + namespace: "petstore" + hostnames: + - example.com + parentRefs: + - name: istio-ingressgateway + namespace: istio-system servers: - url: https://example.io/v1 paths: diff --git a/doc/openapi-apicurio.md b/doc/openapi-apicurio.md index 9dbdbb2..e9b4d2c 100644 --- a/doc/openapi-apicurio.md +++ b/doc/openapi-apicurio.md @@ -18,20 +18,21 @@ Open or import your OpenAPI spec in the Apicurio Studio UI. You can modify the source of the spec from the UI. There are a few different configuration and extension points supported by Apicurio Studio, and also supported by the `kuadrantctl` cli. -To generate a [HTTPRoute](https://gateway-api.sigs.k8s.io/api-types/httproute/) for the API, add the following `x-kuadrant` block to your spec in the UI, replacing values to match your APIs details and the location of your Gateway. +To generate a [HTTPRoute](https://gateway-api.sigs.k8s.io/api-types/httproute/) for the API, +add the following `x-kuadrant` block to the root of your spec in the UI, +replacing values to match your APIs details and the location of your Gateway. ```yaml -info: - x-kuadrant: - route: - name: petstore - namespace: petstore - hostnames: - - 'petstore.example.com' - parentRefs: - - name: prod-web - namespace: kuadrant-multi-cluster-gateways - kind: Gateway +x-kuadrant: + route: + name: petstore + namespace: petstore + hostnames: + - 'petstore.example.com' + parentRefs: + - name: prod-web + namespace: kuadrant-multi-cluster-gateways + kind: Gateway ``` See [this guide](./generate-gateway-api-httproute.md) for more info on generating a HTTPRoute. diff --git a/doc/openapi-kuadrant-extensions.md b/doc/openapi-kuadrant-extensions.md index 3f2ca70..5cc6b60 100644 --- a/doc/openapi-kuadrant-extensions.md +++ b/doc/openapi-kuadrant-extensions.md @@ -1,22 +1,21 @@ ## OpenAPI 3.0.X Kuadrant Extensions -### Info level kuadrant extension +### Root level kuadrant extension -Kuadrant extension that can be added at the info level of the OpenAPI spec. +Kuadrant extension that can be added at the root level of the OpenAPI spec. ```yaml -info: - x-kuadrant: - route: ## HTTPRoute metadata - name: "petstore" - namespace: "petstore" - labels: ## map[string]string - deployment: petstore - hostnames: ## []gateway.networking.k8s.io/v1beta1.Hostname - - example.com - parentRefs: ## []gateway.networking.k8s.io/v1beta1.ParentReference - - name: apiGateway - namespace: gateways +x-kuadrant: + route: ## HTTPRoute metadata + name: "petstore" + namespace: "petstore" + labels: ## map[string]string + deployment: petstore + hostnames: ## []gateway.networking.k8s.io/v1beta1.Hostname + - example.com + parentRefs: ## []gateway.networking.k8s.io/v1beta1.ParentReference + - name: apiGateway + namespace: gateways ``` ### Path level kuadrant extension diff --git a/doc/openapi-openshift-dev-spaces.md b/doc/openapi-openshift-dev-spaces.md index d579ef1..cb9d97f 100644 --- a/doc/openapi-openshift-dev-spaces.md +++ b/doc/openapi-openshift-dev-spaces.md @@ -64,27 +64,26 @@ In this tutorial, we're going to introduce some Kuadrant policies via this OAS. ### Defining a Gateway -Utilize the `x-kuadrant` extension in the `info` block to specify a `Gateway`. This information will be used to generate `HTTPRoute`s at the path level: +Utilize the `x-kuadrant` extension in the root level of your OAS document to specify a `Gateway`. +This information will be used to generate `HTTPRoute`s at the path level: For example: ```yaml -info: - x-kuadrant: - route: ## HTTPRoute metadata - name: "petstore" - namespace: "petstore" - labels: ## map[string]string - deployment: petstore - hostnames: ## []gateway.networking.k8s.io/v1beta1.Hostname - - example.com - parentRefs: ## []gateway.networking.k8s.io/v1beta1.ParentReference - - name: apiGateway - namespace: gateways +x-kuadrant: + route: ## HTTPRoute metadata + name: "petstore" + namespace: "petstore" + labels: ## map[string]string + deployment: petstore + hostnames: ## []gateway.networking.k8s.io/v1beta1.Hostname + - example.com + parentRefs: ## []gateway.networking.k8s.io/v1beta1.ParentReference + - name: apiGateway + namespace: gateways ``` -Add this extension to the `info` section. - +Add this extension to the root section of the OAS document. ### Specifing `HTTPRoute`'s for each Path diff --git a/examples/oas3/petstore-multiple-sec-requirements.yaml b/examples/oas3/petstore-multiple-sec-requirements.yaml index 91b2184..a7b6c0c 100644 --- a/examples/oas3/petstore-multiple-sec-requirements.yaml +++ b/examples/oas3/petstore-multiple-sec-requirements.yaml @@ -3,15 +3,15 @@ openapi: "3.1.0" info: title: "Pet Store API" version: "1.0.0" - x-kuadrant: - route: - name: "petstore" - namespace: "petstore" - hostnames: - - example.com - parentRefs: - - name: istio-ingressgateway - namespace: istio-system +x-kuadrant: + route: + name: "petstore" + namespace: "petstore" + hostnames: + - example.com + parentRefs: + - name: istio-ingressgateway + namespace: istio-system servers: - url: https://toplevel.example.io/v1 paths: diff --git a/examples/oas3/petstore-with-oidc-kuadrant-extensions.yaml b/examples/oas3/petstore-with-oidc-kuadrant-extensions.yaml index cdcc0b8..b81d8bc 100644 --- a/examples/oas3/petstore-with-oidc-kuadrant-extensions.yaml +++ b/examples/oas3/petstore-with-oidc-kuadrant-extensions.yaml @@ -3,15 +3,15 @@ openapi: "3.0.3" info: title: "Pet Store API" version: "1.0.0" - x-kuadrant: - route: - name: "petstore" - namespace: "petstore" - hostnames: - - example.com - parentRefs: - - name: istio-ingressgateway - namespace: istio-system +x-kuadrant: + route: + name: "petstore" + namespace: "petstore" + hostnames: + - example.com + parentRefs: + - name: istio-ingressgateway + namespace: istio-system servers: - url: https://example.io/api/v1 paths: diff --git a/examples/oas3/petstore-with-rate-limit-kuadrant-extensions.yaml b/examples/oas3/petstore-with-rate-limit-kuadrant-extensions.yaml index f6e5548..0c1d6b5 100644 --- a/examples/oas3/petstore-with-rate-limit-kuadrant-extensions.yaml +++ b/examples/oas3/petstore-with-rate-limit-kuadrant-extensions.yaml @@ -3,15 +3,15 @@ openapi: "3.0.3" info: title: "Pet Store API" version: "1.0.0" - x-kuadrant: - route: - name: "petstore" - namespace: "petstore" - hostnames: - - example.com - parentRefs: - - name: istio-ingressgateway - namespace: istio-system +x-kuadrant: + route: + name: "petstore" + namespace: "petstore" + hostnames: + - example.com + parentRefs: + - name: istio-ingressgateway + namespace: istio-system servers: - url: https://example.io/api/v1 paths: diff --git a/pkg/gatewayapi/http_route.go b/pkg/gatewayapi/http_route.go index 4217bbd..2868e0a 100644 --- a/pkg/gatewayapi/http_route.go +++ b/pkg/gatewayapi/http_route.go @@ -10,80 +10,67 @@ import ( ) func HTTPRouteObjectMetaFromOAS(doc *openapi3.T) metav1.ObjectMeta { - if doc.Info == nil { - return metav1.ObjectMeta{} - } - - kuadrantInfoExtension, err := utils.NewKuadrantOASInfoExtension(doc.Info) + kuadrantRootExtension, err := utils.NewKuadrantOASRootExtension(doc) if err != nil { panic(err) } - if kuadrantInfoExtension == nil { + if kuadrantRootExtension == nil { return metav1.ObjectMeta{} } - if kuadrantInfoExtension.Route == nil { - panic("info kuadrant extension route not found") + if kuadrantRootExtension.Route == nil { + panic("openapi root kuadrant extension route not found") } - if kuadrantInfoExtension.Route.Name == nil { - panic("info kuadrant extension route name not found") + if kuadrantRootExtension.Route.Name == nil { + panic("openapi root kuadrant extension route name not found") } om := metav1.ObjectMeta{ - Name: *kuadrantInfoExtension.Route.Name, - Labels: kuadrantInfoExtension.Route.Labels, + Name: *kuadrantRootExtension.Route.Name, + Labels: kuadrantRootExtension.Route.Labels, } - if kuadrantInfoExtension.Route.Namespace != nil { - om.Namespace = *kuadrantInfoExtension.Route.Namespace + if kuadrantRootExtension.Route.Namespace != nil { + om.Namespace = *kuadrantRootExtension.Route.Namespace } return om } func HTTPRouteGatewayParentRefsFromOAS(doc *openapi3.T) []gatewayapiv1.ParentReference { - if doc.Info == nil { - return nil - } - - kuadrantInfoExtension, err := utils.NewKuadrantOASInfoExtension(doc.Info) - + kuadrantRootExtension, err := utils.NewKuadrantOASRootExtension(doc) if err != nil { panic(err) } - if kuadrantInfoExtension == nil { + if kuadrantRootExtension == nil { return nil } - if kuadrantInfoExtension.Route == nil { - panic("info kuadrant extension route not found") + if kuadrantRootExtension.Route == nil { + panic("openapi root kuadrant extension route not found") } - return kuadrantInfoExtension.Route.ParentRefs + return kuadrantRootExtension.Route.ParentRefs } func HTTPRouteHostnamesFromOAS(doc *openapi3.T) []gatewayapiv1.Hostname { - if doc.Info == nil { - return nil - } - - kuadrantInfoExtension, err := utils.NewKuadrantOASInfoExtension(doc.Info) + kuadrantRootExtension, err := utils.NewKuadrantOASRootExtension(doc) if err != nil { panic(err) } - if kuadrantInfoExtension == nil { + if kuadrantRootExtension == nil { return nil } - if kuadrantInfoExtension.Route == nil { - panic("info kuadrant extension route not found") + if kuadrantRootExtension.Route == nil { + panic("openapi root kuadrant extension route not found") } - return kuadrantInfoExtension.Route.Hostnames + return kuadrantRootExtension.Route.Hostnames } func HTTPRouteRulesFromOAS(doc *openapi3.T) []gatewayapiv1.HTTPRouteRule { diff --git a/pkg/utils/kuadrant_oas_extension_types.go b/pkg/utils/kuadrant_oas_extension_types.go index 1816313..8d99028 100644 --- a/pkg/utils/kuadrant_oas_extension_types.go +++ b/pkg/utils/kuadrant_oas_extension_types.go @@ -4,9 +4,10 @@ import ( "encoding/json" "github.com/getkin/kin-openapi/openapi3" - kuadrantapiv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" "k8s.io/utils/ptr" gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" + + kuadrantapiv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" ) type RouteObject struct { @@ -17,22 +18,22 @@ type RouteObject struct { Labels map[string]string `json:"labels,omitempty"` } -type KuadrantOASInfoExtension struct { +type KuadrantOASRootExtension struct { Route *RouteObject `json:"route,omitempty"` } -func NewKuadrantOASInfoExtension(info *openapi3.Info) (*KuadrantOASInfoExtension, error) { - type KuadrantOASInfoObject struct { +func NewKuadrantOASRootExtension(doc *openapi3.T) (*KuadrantOASRootExtension, error) { + type KuadrantOASRootObject struct { // Kuadrant extension - Kuadrant *KuadrantOASInfoExtension `json:"x-kuadrant,omitempty"` + Kuadrant *KuadrantOASRootExtension `json:"x-kuadrant,omitempty"` } - data, err := info.MarshalJSON() + data, err := doc.MarshalJSON() if err != nil { return nil, err } - var x KuadrantOASInfoObject + var x KuadrantOASRootObject if err := json.Unmarshal(data, &x); err != nil { return nil, err }