diff --git a/.github/workflows/code-style.yaml b/.github/workflows/code-style.yaml
index 091a7bf..5e5e226 100644
--- a/.github/workflows/code-style.yaml
+++ b/.github/workflows/code-style.yaml
@@ -9,10 +9,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- - name: Set up Go 1.16.x
- uses: actions/setup-go@v2
+ - name: Set up Go 1.21.x
+ uses: actions/setup-go@v4
with:
- go-version: 1.16.x
+ go-version: 1.21.x
id: go
- name: Check out code
diff --git a/.github/workflows/commands.yaml b/.github/workflows/commands.yaml
index 4d7b1c1..272ff58 100644
--- a/.github/workflows/commands.yaml
+++ b/.github/workflows/commands.yaml
@@ -12,16 +12,18 @@ jobs:
install:
name: Run kuadrantctl install
runs-on: ubuntu-latest
+ env:
+ KIND_CLUSTER_NAME: kuadrantctl-local
steps:
- - name: Set up Go 1.20.x
+ - name: Set up Go 1.21.x
uses: actions/setup-go@v4
with:
- go-version: 1.20.x
+ go-version: 1.21.x
id: go
- name: Check out code
uses: actions/checkout@v3
- name: Create k8s Kind Cluster
- uses: helm/kind-action@v1.2.0
+ uses: helm/kind-action@v1.8.0
with:
version: v0.20.0
config: utils/kind-cluster.yaml
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
new file mode 100644
index 0000000..d667e88
--- /dev/null
+++ b/.github/workflows/release.yaml
@@ -0,0 +1,29 @@
+---
+
+name: Release
+
+on:
+ release:
+ types: [created]
+
+permissions:
+ contents: write
+ packages: write
+
+jobs:
+ release-matrix:
+ name: Release Go Binary
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ # build and publish in parallel: linux/amd64, linux/arm64, darwin/amd64, darwin/arm64
+ goos: [linux, darwin]
+ goarch: [amd64, arm64]
+ steps:
+ - uses: actions/checkout@v3
+ - uses: wangyoucao577/go-release-action@v1
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ goos: ${{ matrix.goos }}
+ goarch: ${{ matrix.goarch }}
+ goversion: 1.21.4
diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml
index 5366111..394bb75 100644
--- a/.github/workflows/testing.yaml
+++ b/.github/workflows/testing.yaml
@@ -13,10 +13,10 @@ jobs:
name: Build executable
runs-on: ubuntu-latest
steps:
- - name: Set up Go 1.20.x
+ - name: Set up Go 1.21.x
uses: actions/setup-go@v4
with:
- go-version: 1.20.x
+ go-version: 1.21.x
id: go
- name: Check out code
uses: actions/checkout@v2
@@ -28,17 +28,17 @@ jobs:
name: Run tests
runs-on: ubuntu-latest
env:
- KIND_CLUSTER_NAME: kuadrant-local
+ KIND_CLUSTER_NAME: kuadrantctl-local
steps:
- - name: Set up Go 1.20.x
+ - name: Set up Go 1.21.x
uses: actions/setup-go@v4
with:
- go-version: 1.20.x
+ go-version: 1.21.x
id: go
- name: Check out code
uses: actions/checkout@v3
- name: Create k8s Kind Cluster
- uses: helm/kind-action@v1.2.0
+ uses: helm/kind-action@v1.8.0
with:
version: v0.20.0
config: utils/kind-cluster.yaml
diff --git a/Makefile b/Makefile
index 0f84025..2a23925 100644
--- a/Makefile
+++ b/Makefile
@@ -53,6 +53,7 @@ env-setup:
$(MAKE) olm-install
$(MAKE) gateway-api-install
$(MAKE) istio-install
+ $(MAKE) deploy-gateway
## local-setup: Sets up Kind cluster with GatewayAPI manifests and istio GW, nothing Kuadrant. Build and install kuadrantctl binary
.PHONY: local-setup
diff --git a/README.md b/README.md
index ea119ba..c3af817 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ Use `go install` to install the latest version of the library. This command will
```
go install github.com/kuadrant/kuadrantctl@latest
```
-> Golang 1.20+ required
+> Golang 1.21+ required
## Commands
* [Install Kuadrant](doc/install.md)
diff --git a/cmd/generate_gatewayapi_httproute.go b/cmd/generate_gatewayapi_httproute.go
index 3ec64f3..fea188d 100644
--- a/cmd/generate_gatewayapi_httproute.go
+++ b/cmd/generate_gatewayapi_httproute.go
@@ -13,73 +13,30 @@ import (
)
var (
- generateGatewayAPIHTTPRouteOAS string
- generateGatewayAPIHTTPRouteHost string
- generateGatewayAPIHTTPRouteSvcName string
- generateGatewayAPIHTTPRouteSvcNamespace string
- generateGatewayAPIHTTPRouteSvcPort int32
- generateGatewayAPIHTTPRouteGateways []string
+ generateGatewayAPIHTTPRouteOAS string
)
-//kuadrantctl generate istio virtualservice --namespace myns --oas petstore.yaml --public-host www.kuadrant.io --service-name myservice --gateway kuadrant-gateway
-// --namespace myns
-// --service-name myservice
-// --public-host www.kuadrant.io
-// --gateway kuadrant-gateway
-// -- service-port 80
+//kuadrantctl generate gatewayapi httproute --oas [OAS_FILE_PATH | OAS_URL | @]
func generateGatewayApiHttpRouteCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "httproute",
- Short: "Generate Gateway API HTTPRoute from OpenAPI 3.x",
- Long: "Generate Gateway API HTTPRoute from OpenAPI 3.x",
- RunE: func(cmd *cobra.Command, args []string) error {
- return generateGatewayApiHttpRoute(cmd, args)
- },
+ Short: "Generate Gateway API HTTPRoute from OpenAPI 3.0.X",
+ Long: "Generate Gateway API HTTPRoute from OpenAPI 3.0.X",
+ RunE: runGenerateGatewayApiHttpRoute,
}
// OpenAPI ref
- cmd.Flags().StringVar(&generateGatewayAPIHTTPRouteOAS, "oas", "", "/path/to/file.[json|yaml|yml] OR http[s]://domain/resource/path.[json|yaml|yml] OR - (required)")
+ cmd.Flags().StringVar(&generateGatewayAPIHTTPRouteOAS, "oas", "", "/path/to/file.[json|yaml|yml] OR http[s]://domain/resource/path.[json|yaml|yml] OR @ (required)")
err := cmd.MarkFlagRequired("oas")
if err != nil {
panic(err)
}
- // service ref
- cmd.Flags().StringVar(&generateGatewayAPIHTTPRouteSvcName, "service-name", "", "Service name (required)")
- err = cmd.MarkFlagRequired("service-name")
- if err != nil {
- panic(err)
- }
-
- // service namespace
- cmd.Flags().StringVarP(&generateGatewayAPIHTTPRouteSvcNamespace, "namespace", "n", "", "Service namespace (required)")
- err = cmd.MarkFlagRequired("namespace")
- if err != nil {
- panic(err)
- }
-
- // service host
- cmd.Flags().StringVar(&generateGatewayAPIHTTPRouteHost, "public-host", "", "Public host (required)")
- err = cmd.MarkFlagRequired("public-host")
- if err != nil {
- panic(err)
- }
-
- // service port
- cmd.Flags().Int32VarP(&generateGatewayAPIHTTPRouteSvcPort, "port", "p", 80, "Service Port (required)")
-
- // gateway
- cmd.Flags().StringSliceVar(&generateGatewayAPIHTTPRouteGateways, "gateway", []string{}, "Gateways (required)")
- err = cmd.MarkFlagRequired("gateway")
- if err != nil {
- panic(err)
- }
-
return cmd
}
-func generateGatewayApiHttpRoute(cmd *cobra.Command, args []string) error {
+func runGenerateGatewayApiHttpRoute(cmd *cobra.Command, args []string) error {
oasDataRaw, err := utils.ReadExternalResource(generateGatewayAPIHTTPRouteOAS)
if err != nil {
return err
@@ -96,10 +53,7 @@ func generateGatewayApiHttpRoute(cmd *cobra.Command, args []string) error {
return fmt.Errorf("OpenAPI validation error: %w", err)
}
- httpRoute, err := generateGatewayAPIHTTPRoute(cmd, doc)
- if err != nil {
- return err
- }
+ httpRoute := buildHTTPRoute(doc)
jsonData, err := json.Marshal(httpRoute)
if err != nil {
@@ -110,52 +64,19 @@ func generateGatewayApiHttpRoute(cmd *cobra.Command, args []string) error {
return nil
}
-func generateGatewayAPIHTTPRoute(cmd *cobra.Command, doc *openapi3.T) (*gatewayapiv1beta1.HTTPRoute, error) {
-
- //loop through gateway
- // https://github.com/getkin/kin-openapi
- gatewaysRef := []gatewayapiv1beta1.ParentReference{}
- for _, gateway := range generateGatewayAPIHTTPRouteGateways {
- gatewaysRef = append(gatewaysRef, gatewayapiv1beta1.ParentReference{
- Name: gatewayapiv1beta1.ObjectName(gateway),
- })
- }
-
- port := gatewayapiv1beta1.PortNumber(generateGatewayAPIHTTPRouteSvcPort)
- service := fmt.Sprintf("%s.%s.svc", generateGatewayAPIHTTPRouteSvcName, generateGatewayAPIHTTPRouteSvcNamespace)
- matches, err := gatewayapi.HTTPRouteMatchesFromOAS(doc)
- if err != nil {
- return nil, err
- }
-
- httpRoute := gatewayapiv1beta1.HTTPRoute{
+func buildHTTPRoute(doc *openapi3.T) *gatewayapiv1beta1.HTTPRoute {
+ return &gatewayapiv1beta1.HTTPRoute{
TypeMeta: v1.TypeMeta{
- Kind: "HTTPRoute",
APIVersion: "gateway.networking.k8s.io/v1beta1",
+ Kind: "HTTPRoute",
},
+ ObjectMeta: gatewayapi.HTTPRouteObjectMetaFromOAS(doc),
Spec: gatewayapiv1beta1.HTTPRouteSpec{
CommonRouteSpec: gatewayapiv1beta1.CommonRouteSpec{
- ParentRefs: gatewaysRef,
- },
- Hostnames: []gatewayapiv1beta1.Hostname{
- gatewayapiv1beta1.Hostname(generateGatewayAPIHTTPRouteHost),
- },
- Rules: []gatewayapiv1beta1.HTTPRouteRule{
- {
- BackendRefs: []gatewayapiv1beta1.HTTPBackendRef{
- {
- BackendRef: gatewayapiv1beta1.BackendRef{
- BackendObjectReference: gatewayapiv1beta1.BackendObjectReference{
- Name: gatewayapiv1beta1.ObjectName(service),
- Port: &port,
- },
- },
- },
- },
- Matches: matches,
- },
+ ParentRefs: gatewayapi.HTTPRouteGatewayParentRefsFromOAS(doc),
},
+ Hostnames: gatewayapi.HTTPRouteHostnamesFromOAS(doc),
+ Rules: gatewayapi.HTTPRouteRulesFromOAS(doc),
},
}
- return &httpRoute, nil
}
diff --git a/cmd/generate_kuadrant.go b/cmd/generate_kuadrant.go
index 0cc73f3..3e575d6 100644
--- a/cmd/generate_kuadrant.go
+++ b/cmd/generate_kuadrant.go
@@ -11,5 +11,8 @@ func generateKuadrantCommand() *cobra.Command {
Long: "Generate Kuadrant resources",
}
+ cmd.AddCommand(generateKuadrantRateLimitPolicyCommand())
+ cmd.AddCommand(generateKuadrantAuthPolicyCommand())
+
return cmd
}
diff --git a/cmd/generate_kuadrant_authpolicy.go b/cmd/generate_kuadrant_authpolicy.go
new file mode 100644
index 0000000..177e50a
--- /dev/null
+++ b/cmd/generate_kuadrant_authpolicy.go
@@ -0,0 +1,97 @@
+package cmd
+
+import (
+ "encoding/json"
+ "fmt"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ kuadrantapiv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2"
+ "github.com/spf13/cobra"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
+ gatewayapiv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
+
+ "github.com/kuadrant/kuadrantctl/pkg/gatewayapi"
+ "github.com/kuadrant/kuadrantctl/pkg/kuadrantapi"
+ "github.com/kuadrant/kuadrantctl/pkg/utils"
+)
+
+//kuadrantctl generate kuadrant authpolicy --oas [OAS_FILE_PATH | OAS_URL | @]
+
+func generateKuadrantAuthPolicyCommand() *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "authpolicy",
+ Short: "Generate Kuadrant AuthPolicy from OpenAPI 3.0.X",
+ Long: "Generate Kuadrant AuthPolicy from OpenAPI 3.0.X",
+ RunE: runGenerateKuadrantAuthPolicy,
+ }
+
+ // OpenAPI ref
+ cmd.Flags().StringVar(&generateGatewayAPIHTTPRouteOAS, "oas", "", "/path/to/file.[json|yaml|yml] OR http[s]://domain/resource/path.[json|yaml|yml] OR @ (required)")
+ err := cmd.MarkFlagRequired("oas")
+ if err != nil {
+ panic(err)
+ }
+
+ return cmd
+}
+
+func runGenerateKuadrantAuthPolicy(cmd *cobra.Command, args []string) error {
+ oasDataRaw, err := utils.ReadExternalResource(generateGatewayAPIHTTPRouteOAS)
+ if err != nil {
+ return err
+ }
+
+ openapiLoader := openapi3.NewLoader()
+ doc, err := openapiLoader.LoadFromData(oasDataRaw)
+ if err != nil {
+ return err
+ }
+
+ err = doc.Validate(openapiLoader.Context)
+ if err != nil {
+ return fmt.Errorf("OpenAPI validation error: %w", err)
+ }
+
+ ap := buildAuthPolicy(doc)
+
+ jsonData, err := json.Marshal(ap)
+ if err != nil {
+ return err
+ }
+
+ fmt.Fprintln(cmd.OutOrStdout(), string(jsonData))
+ return nil
+}
+
+func buildAuthPolicy(doc *openapi3.T) *kuadrantapiv1beta2.AuthPolicy {
+ routeMeta := gatewayapi.HTTPRouteObjectMetaFromOAS(doc)
+
+ ap := &kuadrantapiv1beta2.AuthPolicy{
+ TypeMeta: v1.TypeMeta{
+ APIVersion: "kuadrant.io/v1beta2",
+ Kind: "AuthPolicy",
+ },
+ ObjectMeta: kuadrantapi.AuthPolicyObjectMetaFromOAS(doc),
+ Spec: kuadrantapiv1beta2.AuthPolicySpec{
+ TargetRef: gatewayapiv1alpha2.PolicyTargetReference{
+ Group: gatewayapiv1beta1.Group("gateway.networking.k8s.io"),
+ Kind: gatewayapiv1beta1.Kind("HTTPRoute"),
+ Name: gatewayapiv1beta1.ObjectName(routeMeta.Name),
+ },
+ // Currently only authentication rules enforced
+ AuthScheme: kuadrantapiv1beta2.AuthSchemeSpec{
+ Authentication: kuadrantapi.AuthPolicyAuthenticationSchemeFromOAS(doc),
+ },
+ RouteSelectors: kuadrantapi.AuthPolicyTopRouteSelectorsFromOAS(doc),
+ },
+ }
+
+ if routeMeta.Namespace != "" {
+ ap.Spec.TargetRef.Namespace = &[]gatewayapiv1beta1.Namespace{
+ gatewayapiv1beta1.Namespace(routeMeta.Namespace),
+ }[0]
+ }
+
+ return ap
+}
diff --git a/cmd/generate_kuadrant_ratelimitpolicy.go b/cmd/generate_kuadrant_ratelimitpolicy.go
new file mode 100644
index 0000000..9115607
--- /dev/null
+++ b/cmd/generate_kuadrant_ratelimitpolicy.go
@@ -0,0 +1,93 @@
+package cmd
+
+import (
+ "encoding/json"
+ "fmt"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ kuadrantapiv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2"
+ "github.com/spf13/cobra"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
+ gatewayapiv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
+
+ "github.com/kuadrant/kuadrantctl/pkg/gatewayapi"
+ "github.com/kuadrant/kuadrantctl/pkg/kuadrantapi"
+ "github.com/kuadrant/kuadrantctl/pkg/utils"
+)
+
+//kuadrantctl generate kuadrant ratelimitpolicy --oas [OAS_FILE_PATH | OAS_URL | @]
+
+func generateKuadrantRateLimitPolicyCommand() *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "ratelimitpolicy",
+ Short: "Generate Kuadrant RateLimitPolicy from OpenAPI 3.0.X",
+ Long: "Generate Kuadrant RateLimitPolicy from OpenAPI 3.0.X",
+ RunE: runGenerateKuadrantRateLimitPolicy,
+ }
+
+ // OpenAPI ref
+ cmd.Flags().StringVar(&generateGatewayAPIHTTPRouteOAS, "oas", "", "/path/to/file.[json|yaml|yml] OR http[s]://domain/resource/path.[json|yaml|yml] OR @ (required)")
+ err := cmd.MarkFlagRequired("oas")
+ if err != nil {
+ panic(err)
+ }
+
+ return cmd
+}
+
+func runGenerateKuadrantRateLimitPolicy(cmd *cobra.Command, args []string) error {
+ oasDataRaw, err := utils.ReadExternalResource(generateGatewayAPIHTTPRouteOAS)
+ if err != nil {
+ return err
+ }
+
+ openapiLoader := openapi3.NewLoader()
+ doc, err := openapiLoader.LoadFromData(oasDataRaw)
+ if err != nil {
+ return err
+ }
+
+ err = doc.Validate(openapiLoader.Context)
+ if err != nil {
+ return fmt.Errorf("OpenAPI validation error: %w", err)
+ }
+
+ rlp := buildRateLimitPolicy(doc)
+
+ jsonData, err := json.Marshal(rlp)
+ if err != nil {
+ return err
+ }
+
+ fmt.Fprintln(cmd.OutOrStdout(), string(jsonData))
+ return nil
+}
+
+func buildRateLimitPolicy(doc *openapi3.T) *kuadrantapiv1beta2.RateLimitPolicy {
+ routeMeta := gatewayapi.HTTPRouteObjectMetaFromOAS(doc)
+
+ rlp := &kuadrantapiv1beta2.RateLimitPolicy{
+ TypeMeta: v1.TypeMeta{
+ APIVersion: "kuadrant.io/v1beta2",
+ Kind: "RateLimitPolicy",
+ },
+ ObjectMeta: kuadrantapi.RateLimitPolicyObjectMetaFromOAS(doc),
+ Spec: kuadrantapiv1beta2.RateLimitPolicySpec{
+ TargetRef: gatewayapiv1alpha2.PolicyTargetReference{
+ Group: gatewayapiv1beta1.Group("gateway.networking.k8s.io"),
+ Kind: gatewayapiv1beta1.Kind("HTTPRoute"),
+ Name: gatewayapiv1beta1.ObjectName(routeMeta.Name),
+ },
+ Limits: kuadrantapi.RateLimitPolicyLimitsFromOAS(doc),
+ },
+ }
+
+ if routeMeta.Namespace != "" {
+ rlp.Spec.TargetRef.Namespace = &[]gatewayapiv1beta1.Namespace{
+ gatewayapiv1beta1.Namespace(routeMeta.Namespace),
+ }[0]
+ }
+
+ return rlp
+}
diff --git a/cmd/install.go b/cmd/install.go
index 9d1741b..c36eaa0 100644
--- a/cmd/install.go
+++ b/cmd/install.go
@@ -101,8 +101,9 @@ func waitForDeployments(k8sClient client.Client) error {
}
for _, key := range deploymentKeys {
- err := wait.Poll(retryInterval, timeout, func() (bool, error) {
- return utils.CheckDeploymentAvailable(k8sClient, key)
+ immediate := true
+ err := wait.PollUntilContextTimeout(context.Background(), retryInterval, timeout, immediate, func(ctx context.Context) (bool, error) {
+ return utils.CheckDeploymentAvailable(ctx, k8sClient, key)
})
if err != nil {
@@ -147,10 +148,11 @@ func deployKuadrantOperator(k8sClient client.Client) error {
var installPlanKey client.ObjectKey
// Wait for the install process to be completed
+ immediate := true
logf.Log.Info("Waiting for the kuadrant operator installation")
- err = wait.Poll(time.Second*2, time.Second*20, func() (bool, error) {
+ err = wait.PollUntilContextTimeout(context.Background(), time.Second*5, time.Minute*2, immediate, func(ctx context.Context) (bool, error) {
existingSubs := &operators.Subscription{}
- err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(subs), existingSubs)
+ err := k8sClient.Get(ctx, client.ObjectKeyFromObject(subs), existingSubs)
if err != nil {
if apierrors.IsNotFound(err) {
logf.Log.Info("Subscription not available", "name", client.ObjectKeyFromObject(subs))
@@ -176,9 +178,9 @@ func deployKuadrantOperator(k8sClient client.Client) error {
}
logf.Log.Info("Waiting for the install plan", "name", installPlanKey)
- err = wait.Poll(time.Second*5, time.Minute*2, func() (bool, error) {
+ err = wait.PollUntilContextTimeout(context.Background(), time.Second*5, time.Minute*2, immediate, func(ctx context.Context) (bool, error) {
ip := &operators.InstallPlan{}
- err := k8sClient.Get(context.Background(), installPlanKey, ip)
+ err := k8sClient.Get(ctx, installPlanKey, ip)
if err != nil {
if apierrors.IsNotFound(err) {
logf.Log.Info("Install plan not available", "name", installPlanKey)
@@ -230,8 +232,9 @@ func createNamespace(k8sClient client.Client) error {
retryInterval := time.Second * 2
timeout := time.Second * 20
- return wait.Poll(retryInterval, timeout, func() (bool, error) {
- err := k8sClient.Get(context.Background(), types.NamespacedName{Name: installNamespace}, &corev1.Namespace{})
+ immediate := true
+ return wait.PollUntilContextTimeout(context.Background(), retryInterval, timeout, immediate, func(ctx context.Context) (bool, error) {
+ err := k8sClient.Get(ctx, types.NamespacedName{Name: installNamespace}, &corev1.Namespace{})
if err != nil && apierrors.IsNotFound(err) {
return false, nil
}
diff --git a/config/gateway-api/gateway/gateway.yaml b/config/gateway-api/gateway/gateway.yaml
new file mode 100644
index 0000000..7886c7a
--- /dev/null
+++ b/config/gateway-api/gateway/gateway.yaml
@@ -0,0 +1,19 @@
+---
+apiVersion: gateway.networking.k8s.io/v1beta1
+kind: Gateway
+metadata:
+ labels:
+ istio: ingressgateway
+ name: istio-ingressgateway
+spec:
+ gatewayClassName: istio
+ listeners:
+ - name: default
+ port: 80
+ protocol: HTTP
+ allowedRoutes:
+ namespaces:
+ from: All
+ addresses:
+ - value: istio-ingressgateway.istio-system.svc.cluster.local
+ type: Hostname
diff --git a/config/gateway-api/gateway/kustomization.yaml b/config/gateway-api/gateway/kustomization.yaml
new file mode 100644
index 0000000..b489ae5
--- /dev/null
+++ b/config/gateway-api/gateway/kustomization.yaml
@@ -0,0 +1,5 @@
+---
+# Adds namespace to all resources.
+namespace: istio-system
+resources:
+- gateway.yaml
diff --git a/doc/development.md b/doc/development.md
index 4c39802..f02e2b1 100644
--- a/doc/development.md
+++ b/doc/development.md
@@ -3,7 +3,7 @@
## Technology stack required for development
* [git][git_tool]
-* [go] version 1.20+
+* [go] version 1.21+
## Build the CLI
```
diff --git a/doc/generate-gateway-api-httproute.md b/doc/generate-gateway-api-httproute.md
index be15a4d..5385332 100644
--- a/doc/generate-gateway-api-httproute.md
+++ b/doc/generate-gateway-api-httproute.md
@@ -1,35 +1,32 @@
## Generate Gateway API HTTPRoute object from OpenAPI 3
The `kuadrantctl generate gatewayapi httproute` command generates an [Gateway API HTTPRoute](https://gateway-api.sigs.k8s.io/v1alpha2/guides/http-routing/)
-from your [OpenAPI Specification (OAS) 3.x](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.2.md) and kubernetes service information.
+from your [OpenAPI Specification (OAS) 3.x](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.2.md) powered with [kuadrant extensions](openapi-kuadrant-extensions.md).
### OpenAPI specification
+[OpenAPI `v3.0`](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md)
+
OpenAPI document resource can be provided by one of the following channels:
* Filename in the available path.
* URL format (supported schemes are HTTP and HTTPS). The CLI will try to download from the given address.
* Read from stdin standard input stream.
-### Usage :
+### Usage
```shell
$ kuadrantctl generate gatewayapi httproute -h
-Generate Gateway API HTTPRoute from OpenAPI 3.x
+Generate Gateway API HTTPRoute from OpenAPI 3.0.X
Usage:
kuadrantctl generate gatewayapi httproute [flags]
Flags:
- --gateway strings Gateways (required)
- -h, --help help for httproute
- -n, --namespace string Service namespace (required)
- --oas string /path/to/file.[json|yaml|yml] OR http[s]://domain/resource/path.[json|yaml|yml] OR - (required)
- -p, --port int32 Service Port (required) (default 80)
- --public-host string Public host (required)
- --service-name string Service name (required)
+ -h, --help help for httproute
+ --oas string /path/to/file.[json|yaml|yml] OR http[s]://domain/resource/path.[json|yaml|yml] OR @ (required)
Global Flags:
-v, --verbose verbose output
```
-> Under the example folder there are examples of OAS 3 that can be used to generate the resources
+> Under the example folder there are examples of OAS 3 that can be used to generate the resources
diff --git a/doc/generate-kuadrant-auth-policy.md b/doc/generate-kuadrant-auth-policy.md
new file mode 100644
index 0000000..732bb5d
--- /dev/null
+++ b/doc/generate-kuadrant-auth-policy.md
@@ -0,0 +1,499 @@
+## Generate Kuadrant AuthPolicy object from OpenAPI 3
+
+The `kuadrantctl generate kuadrant authpolicy` command generates an [Kuadrant AuthPolicy](https://github.com/Kuadrant/kuadrant-operator/blob/v0.4.1/doc/auth.md)
+from your [OpenAPI Specification (OAS) 3.x](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.2.md) powered with [kuadrant extensions](openapi-kuadrant-extensions.md).
+
+### OpenAPI specification
+
+[OpenAPI `v3.0`](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md)
+
+OpenAPI document resource can be provided by one of the following channels:
+* Filename in the available path.
+* URL format (supported schemes are HTTP and HTTPS). The CLI will try to download from the given address.
+* Read from stdin standard input stream.
+
+OpenAPI [Security Scheme Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#security-scheme-object) types
+
+| Types | Implemented |
+| --- | --- |
+| `openIdConnect` | **YES** |
+| `apiKey` | **YES** |
+| `http` | NO |
+| `oauth2` | NO |
+
+### `openIdConnect` Type Description
+
+The following OAS example has one protected endpoint `GET /dog` with `openIdConnect` security scheme type.
+
+```yaml
+paths:
+ /dog:
+ get:
+ operationId: "getDog"
+ security:
+ - securedDog: []
+ responses:
+ 405:
+ description: "invalid input"
+components:
+ securitySchemes:
+ securedDog:
+ type: openIdConnect
+ openIdConnectUrl: https://example.com/.well-known/openid-configuration
+```
+
+Running the command
+
+```
+kuadrantctl generate kuadrant authpolicy --oas ./petstore-openapi.yaml | yq -P
+```
+
+The generated authpolicy (only relevan fields shown here):
+
+```yaml
+kind: AuthPolicy
+apiVersion: kuadrant.io/v1beta2
+metadata:
+ name: petstore
+ namespace: petstore
+ creationTimestamp: null
+spec:
+ routeSelectors:
+ - matches:
+ - path:
+ type: Exact
+ value: /api/v1/dog
+ method: GET
+ rules:
+ authentication:
+ getDog_securedDog:
+ credentials: {}
+ jwt:
+ issuerUrl: https://example.com/.well-known/openid-configuration
+ routeSelectors:
+ - matches:
+ - path:
+ type: Exact
+ value: /api/v1/dog
+ method: GET
+```
+
+### `apiKey` Type Description
+
+The following OAS example has one protected endpoint `GET /dog` with `apiKey` security scheme type.
+
+```yaml
+paths:
+ /dog:
+ get:
+ operationId: "getDog"
+ security:
+ - securedDog: []
+ responses:
+ 405:
+ description: "invalid input"
+components:
+ securitySchemes:
+ securedDog:
+ type: apiKey
+ name: dog_token
+ in: query
+```
+
+Running the command
+
+```
+kuadrantctl generate kuadrant authpolicy --oas ./petstore-openapi.yaml | yq -P
+```
+
+The generated authpolicy (only relevan fields shown here):
+
+```yaml
+kind: AuthPolicy
+apiVersion: kuadrant.io/v1beta2
+metadata:
+ name: petstore
+ namespace: petstore
+ creationTimestamp: null
+spec:
+ routeSelectors:
+ - matches:
+ - path:
+ type: Exact
+ value: /dog
+ method: GET
+ rules:
+ authentication:
+ getDog_securedDog:
+ credentials:
+ queryString:
+ name: dog_token
+ apiKey:
+ selector:
+ matchLabels:
+ kuadrant.io/apikeys-by: securedDog
+ routeSelectors:
+ - matches:
+ - path:
+ type: Exact
+ value: /dog
+ method: GET
+```
+
+In this particular example, the endpoint `GET /dog` will be protected.
+The token needs to be in the query string of the request included in a parameter named `dog_token`.
+Kuadrant will validate received tokens against tokens found in kubernetes secrets with label `kuadrant.io/apikeys-by: ${sec scheme name}`.
+In this particular example the label selector will be: `kuadrant.io/apikeys-by: securedDog`.
+
+Like the following example:
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: api-key-1
+ labels:
+ authorino.kuadrant.io/managed-by: authorino
+ kuadrant.io/apikeys-by: securedDog
+stringData:
+ api_key: MYSECRETTOKENVALUE
+type: Opaque
+```
+> **Note**: Kuadrant validates tokens against api keys found in secrets. The label selector format `kuadrant.io/apikeys-by: ${sec scheme name}` is arbitrary and designed for this CLI command.
+
+For more information about Kuadrant auth based on api key: https://docs.kuadrant.io/authorino/docs/user-guides/api-key-authentication/
+
+### Usage
+
+```shell
+Generate Kuadrant AuthPolicy from OpenAPI 3.0.X
+
+Usage:
+ kuadrantctl generate kuadrant authpolicy [flags]
+
+Flags:
+ -h, --help help for authpolicy
+ --oas string /path/to/file.[json|yaml|yml] OR http[s]://domain/resource/path.[json|yaml|yml] OR @ (required)
+
+Global Flags:
+ -v, --verbose verbose output
+```
+
+> Under the example folder there are examples of OAS 3 that can be used to generate the resources
+
+### User Guide
+
+The verification steps will lead you to the process of deploying and testing the following api with
+endpoints protected using different security schemes:
+
+| Operation | Security Scheme |
+| --- | --- |
+| `GET /api/v1/cat` | public (not auth) |
+| `POST /api/v1/cat` | ApiKey in header |
+| `GET /api/v1/dog` | OpenIdConnect |
+| `GET /api/v1/snake` | OpenIdConnect **OR** ApiKey in query string |
+
+* [Optional] Setup SSO service supporting OIDC. For this example, we will be using [keycloak](https://www.keycloak.org).
+ * Create a new realm `petstore`
+ * Create a client `petstore`. In the Client Protocol field, select `openid-connect`.
+ * Configure client settings. Access Type to public. Direct Access Grants Enabled to ON (for this example password will be used directly to generate the token).
+ * Add a user to the realm
+ * Click the Users menu on the left side of the window. Click Add user.
+ * Type the username `bob`, set the Email Verified switch to ON, and click Save.
+ * On the Credentials tab, set the password `p`. Enter the password in both the fields, set the Temporary switch to OFF to avoid the password reset at the next login, and click `Set Password`.
+
+Now, let's run local cluster to test the kuadrantctl new command to generate authpolicy.
+
+* Clone the repo
+
+```bash
+git clone https://github.com/Kuadrant/kuadrantctl.git
+cd kuadrantctl
+```
+
+* Setup cluster, istio and Gateway API CRDs
+
+```bash
+make local-setup
+```
+
+* Build and install CLI in `bin/kuadrantctl` path
+
+```bash
+make install
+```
+
+* Install Kuadrant service protection. The CLI can be used to install kuadrant v0.4.1
+
+```bash
+bin/kuadrantctl install
+```
+
+* Deploy petstore backend API
+
+```bash
+kubectl create namespace petstore
+kubectl apply -n petstore -f examples/petstore/petstore.yaml
+```
+
+* Let's create Petstore's OpenAPI spec
+
+
+
+```yaml
+cat <petstore-openapi.yaml
+---
+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
+servers:
+ - url: https://example.io/api/v1
+paths:
+ /cat:
+ x-kuadrant:
+ backendRefs:
+ - name: petstore
+ port: 80
+ namespace: petstore
+ get: # No sec requirements
+ operationId: "getCat"
+ responses:
+ 405:
+ description: "invalid input"
+ post: # API key
+ operationId: "postCat"
+ security:
+ - cat_api_key: []
+ responses:
+ 405:
+ description: "invalid input"
+ /dog:
+ x-kuadrant:
+ backendRefs:
+ - name: petstore
+ port: 80
+ namespace: petstore
+ get: # OIDC
+ operationId: "getDog"
+ security:
+ - oidc:
+ - read:dogs
+ responses:
+ 405:
+ description: "invalid input"
+ /snake:
+ x-kuadrant:
+ backendRefs:
+ - name: petstore
+ port: 80
+ namespace: petstore
+ get: # OIDC or API key
+ operationId: "getSnake"
+ security:
+ - oidc: ["read:snakes"]
+ - snakes_api_key: []
+ responses:
+ 405:
+ description: "invalid input"
+components:
+ securitySchemes:
+ cat_api_key:
+ type: apiKey
+ name: api_key
+ in: header
+ oidc:
+ type: openIdConnect
+ openIdConnectUrl: https://${KEYCLOAK_PUBLIC_DOMAIN}/auth/realms/petstore
+ snakes_api_key:
+ type: apiKey
+ name: snake_token
+ in: query
+EOF
+```
+
+
+
+> Replace `${KEYCLOAK_PUBLIC_DOMAIN}` with your SSO instance domain
+
+* Create an API key only valid for `POST /api/v1/cat` endpoint
+```yaml
+kubectl apply -f -< **Note**: the label's value of `kuadrant.io/apikeys-by: cat_api_key` is the name of the sec scheme of the OpenAPI spec.
+
+* Create an API key only valid for `GET /api/v1/snake` endpoint
+
+```yaml
+kubectl apply -f -< **Note**: the label's value of `kuadrant.io/apikeys-by: snakes_api_key` is the name of the sec scheme of the OpenAPI spec.
+
+* Create the HTTPRoute using the CLI
+
+```bash
+bin/kuadrantctl generate gatewayapi httproute --oas petstore-openapi.yaml | kubectl apply -n petstore -f -
+```
+
+* Create Kuadrant's Auth Policy
+
+```bash
+bin/kuadrantctl generate kuadrant authpolicy --oas petstore-openapi.yaml | kubectl apply -n petstore -f -
+```
+
+Now, we are ready to test OpenAPI endpoints :exclamation:
+
+- `GET /api/v1/cat` -> It's a public endpoint, hence should return 200 Ok
+
+```bash
+curl -H "Host: example.com" -i "http://127.0.0.1:9080/api/v1/cat"
+```
+
+- `POST /api/v1/cat` -> It's a protected endpoint with apikey
+
+Without any credentials, it should return `401 Unauthorized`
+
+```bash
+curl -H "Host: example.com" -X POST -i "http://127.0.0.1:9080/api/v1/cat"
+```
+
+```
+HTTP/1.1 401 Unauthorized
+www-authenticate: Bearer realm="getDog_oidc"
+www-authenticate: Bearer realm="getSnake_oidc"
+www-authenticate: snake_token realm="getSnake_snakes_api_key"
+www-authenticate: api_key realm="postCat_cat_api_key"
+x-ext-auth-reason: {"postCat_cat_api_key":"credential not found"}
+date: Tue, 28 Nov 2023 22:28:44 GMT
+server: istio-envoy
+content-length: 0
+```
+
+The *reason* headers tell that `credential not found`.
+Credentials satisfying `postCat_cat_api_key` authentication is needed.
+
+According to the OpenAPI spec, it should be a header named `api_key`.
+What if we try a wrong token? one token assigned to other endpoint,
+i.e. `I_LIKE_SNAKES` instead of the valid one `I_LIKE_CATS`. It should return `401 Unauthorized`.
+
+```bash
+curl -H "Host: example.com" -H "api_key: I_LIKE_SNAKES" -X POST -i "http://127.0.0.1:9080/api/v1/cat"
+```
+
+```
+TTP/1.1 401 Unauthorized
+www-authenticate: Bearer realm="getDog_oidc"
+www-authenticate: Bearer realm="getSnake_oidc"
+www-authenticate: snake_token realm="getSnake_snakes_api_key"
+www-authenticate: api_key realm="postCat_cat_api_key"
+x-ext-auth-reason: {"postCat_cat_api_key":"the API Key provided is invalid"}
+date: Tue, 28 Nov 2023 22:32:55 GMT
+server: istio-envoy
+content-length: 0
+```
+
+The *reason* headers tell that `the API Key provided is invalid`.
+Using valid token (from the secret `cat-api-key-1` assigned to `POST /api/v1/cats`)
+in the `api_key` header should return 200 Ok
+
+```
+curl -H "Host: example.com" -H "api_key: I_LIKE_CATS" -X POST -i "http://127.0.0.1:9080/api/v1/cat"
+```
+
+- `GET /api/v1/dog` -> It's a protected endpoint with oidc (assigned to our keycloak instance and `petstore` realm)
+
+without credentials, it should return `401 Unauthorized`
+
+```bash
+curl -H "Host: example.com" -i "http://127.0.0.1:9080/api/v1/dog"
+```
+
+To get the authentication token, this example is using Direct Access Grants oauth2 grant type
+(also known as Client Credentials grant type). When configuring the Keycloak (OIDC provider) client
+settings, we enabled Direct Access Grants to enable this procedure.
+We will be authenticating as `bob` user with `p` password.
+We previously created `bob` user in Keycloak in the `petstore` realm.
+
+```
+export ACCESS_TOKEN=$(curl -k -H "Content-Type: application/x-www-form-urlencoded" \
+ -d 'grant_type=password' \
+ -d 'client_id=petstore' \
+ -d 'scope=openid' \
+ -d 'username=bob' \
+ -d 'password=p' "https://${KEYCLOAK_PUBLIC_DOMAIN}/auth/realms/petstore/protocol/openid-connect/token" | jq -r '.access_token')
+```
+
+> Replace `${KEYCLOAK_PUBLIC_DOMAIN}` with your SSO instance domain
+
+
+With the access token in place, let's try to get those puppies
+
+```bash
+curl -H "Authorization: Bearer $ACCESS_TOKEN" -H 'Host: example.com' http://127.0.0.1:9080/api/v1/dog -i
+```
+
+it should return 200 OK
+
+- `GET /api/v1/snake` -> It's a protected endpoint with oidc (assigned to our keycloak instance and `petstore` realm) **OR** with apiKey
+
+This example is to show that multiple security requirements (with *OR* semantics) can be specified
+for an OpenAPI operation.
+
+Without credentials, it should return `401 Unauthorized`
+
+```bash
+curl -H "Host: example.com" -i "http://127.0.0.1:9080/api/v1/snake"
+```
+
+With the access token in place, it should return 200 OK (unless the token has expired).
+
+```bash
+curl -H "Authorization: Bearer $ACCESS_TOKEN" -H 'Host: example.com' http://127.0.0.1:9080/api/v1/snake -i
+```
+
+With apiKey it should also work. According to the OpenAPI spec security scheme,
+it should be a query string named `snake_token` and the token needs to be valid token
+(from the secret `snake-api-key-1` assigned to `GET /api/v1/snake`)
+
+```bash
+curl -H 'Host: example.com' -i "http://127.0.0.1:9080/api/v1/snake?snake_token=I_LIKE_SNAKES"
+```
+
+* Clean environment
+```bash
+make local-cleanup
+```
diff --git a/doc/generate-kuadrant-rate-limit-policy.md b/doc/generate-kuadrant-rate-limit-policy.md
new file mode 100644
index 0000000..7a5dbee
--- /dev/null
+++ b/doc/generate-kuadrant-rate-limit-policy.md
@@ -0,0 +1,183 @@
+## Generate Kuadrant RateLimitPolicy object from OpenAPI 3
+
+The `kuadrantctl generate kuadrant ratelimitpolicy` command generates an [Kuadrant RateLimitPolicy](https://github.com/Kuadrant/kuadrant-operator/blob/v0.4.1/doc/rate-limiting.md)
+from your [OpenAPI Specification (OAS) 3.x](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.2.md) powered with [kuadrant extensions](openapi-kuadrant-extensions.md).
+
+### OpenAPI specification
+
+[OpenAPI `v3.0`](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md)
+
+OpenAPI document resource can be provided by one of the following channels:
+* Filename in the available path.
+* URL format (supported schemes are HTTP and HTTPS). The CLI will try to download from the given address.
+* Read from stdin standard input stream.
+
+### Usage
+
+```shell
+Generate Kuadrant RateLimitPolicy from OpenAPI 3.0.X
+
+Usage:
+ kuadrantctl generate kuadrant ratelimitpolicy [flags]
+
+Flags:
+ -h, --help help for ratelimitpolicy
+ --oas string /path/to/file.[json|yaml|yml] OR http[s]://domain/resource/path.[json|yaml|yml] OR @ (required)
+
+Global Flags:
+ -v, --verbose verbose output
+```
+
+> Under the example folder there are examples of OAS 3 that can be used to generate the resources
+
+### User Guide
+
+* Clone the repo
+```bash
+git clone https://github.com/Kuadrant/kuadrantctl.git
+cd kuadrantctl
+```
+* Setup cluster, istio and Gateway API CRDs
+```bash
+make local-setup
+```
+* Build and install CLI in `bin/kuadrantctl` path
+```bash
+make install
+```
+* Install Kuadrant service protection. The CLI can be used to install kuadrant v0.4.1
+```bash
+bin/kuadrantctl install
+```
+* Deploy petstore backend API
+```bash
+kubectl create namespace petstore
+kubectl apply -n petstore -f examples/petstore/petstore.yaml
+```
+* Let's create Petstore's OpenAPI spec
+
+
+
+```yaml
+cat <petstore-openapi.yaml
+---
+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
+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 and NOT rate limited
+ x-kuadrant: ## Operation level Kuadrant Extension
+ backendRefs:
+ - name: petstore
+ port: 80
+ namespace: petstore
+ operationId: "postDog"
+ responses:
+ 405:
+ description: "invalid input"
+EOF
+```
+
+
+
+> **NOTE**: `servers` base path not included. WIP in following up PRs.
+
+| Operation | Applied config |
+| --- | --- |
+| `GET /cat` | It should return 200 Ok and be rate limited (1 req / 10 seconds) |
+| `POST /cat` | Not added to the HTTPRoute. It should return 404 Not Found |
+| `GET /dog` | It should return 200 Ok and be rate limited (3 req / 10 seconds) |
+| `POST /dog` | It should return 200 Ok and NOT rate limited |
+
+
+* Create the HTTPRoute using the CLI
+```bash
+bin/kuadrantctl generate gatewayapi httproute --oas petstore-openapi.yaml | kubectl apply -n petstore -f -
+```
+
+* Create the Rate Limit Policy
+```bash
+bin/kuadrantctl generate kuadrant ratelimitpolicy --oas petstore-openapi.yaml | kubectl apply -n petstore -f -
+```
+
+* Test OpenAPI endpoints
+ * `GET /cat` -> It should return 200 Ok and be rate limited (1 req / 10 seconds)
+
+```bash
+curl --resolve example.com:9080:127.0.0.1 -v "http://example.com:9080/cat"
+```
+ * `POST /cat` -> Not added to the HTTPRoute. It should return 404 Not Found
+```bash
+curl --resolve example.com:9080:127.0.0.1 -v -X POST "http://example.com:9080/cat"
+```
+ * `GET /dog` -> It should return 200 Ok and be rate limited (3 req / 10 seconds)
+
+```bash
+curl --resolve example.com:9080:127.0.0.1 -v "http://example.com:9080/dog"
+```
+
+ * `POST /dog` -> It should return 200 Ok and NOT rate limited
+
+```bash
+curl --resolve example.com:9080:127.0.0.1 -v -X POST "http://example.com:9080/dog"
+```
+
+* Clean environment
+```bash
+make local-cleanup
+```
diff --git a/doc/openapi-kuadrant-extensions.md b/doc/openapi-kuadrant-extensions.md
new file mode 100644
index 0000000..3f2ca70
--- /dev/null
+++ b/doc/openapi-kuadrant-extensions.md
@@ -0,0 +1,78 @@
+## OpenAPI 3.0.X Kuadrant Extensions
+
+### Info level kuadrant extension
+
+Kuadrant extension that can be added at the info 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
+```
+
+### Path level kuadrant extension
+
+Kuadrant extension that can be added at the path level of the OpenAPI spec.
+This configuration at the path level
+is the default when there is no operation level configuration.
+
+```yaml
+paths:
+ /cat:
+ x-kuadrant: ## Path level Kuadrant Extension
+ disable: true ## Remove from the HTTPRoute. Optional. Default: false
+ pathMatchType: Exact ## Specifies how to match against the path Value. Valid values: [Exact;PathPrefix]. Optional. Default: Exact
+ backendRefs: ## Backend references to be included in the HTTPRoute. []gateway.networking.k8s.io/v1beta1.HTTPBackendRef. Optional.
+ - name: petstore
+ port: 80
+ namespace: petstore
+ rate_limit: ## Rate limit config. Optional.
+ rates: ## Kuadrant API []github.com/kuadrant/kuadrant-operator/api/v1beta2.Rate
+ - limit: 1
+ duration: 10
+ unit: second
+ counters: ## Kuadrant API []github.com/kuadrant/kuadrant-operator/api/v1beta2.CountextSelector
+ - auth.identity.username
+ when: ## Kuadrant API []github.com/kuadrant/kuadrant-operator/api/v1beta2.WhenCondition
+ - selector: metadata.filter_metadata.envoy\.filters\.http\.ext_authz.identity.userid
+ operator: eq
+ value: alice
+```
+
+### Operation level kuadrant extension
+
+Kuadrant extension that can be added at the operation level of the OpenAPI spec.
+Same schema as path level kuadrant extension.
+
+```yaml
+paths:
+ /cat:
+ get:
+ x-kuadrant: ## Path level Kuadrant Extension
+ disable: true ## Remove from the HTTPRoute. Optional. Default: path level "disable" value
+ pathMatchType: Exact ## Specifies how to match against the path Value. Valid values: [Exact;PathPrefix]. Optional. Default: Exact
+ backendRefs: ## Backend references to be included in the HTTPRoute. Optional.
+ - name: petstore
+ port: 80
+ namespace: petstore
+ rate_limit: ## Rate limit config. Optional.
+ rates: ## Kuadrant API github.com/kuadrant/kuadrant-operator/api/v1beta2.Rate
+ - limit: 1
+ duration: 10
+ unit: second
+ counters: ## Kuadrant API github.com/kuadrant/kuadrant-operator/api/v1beta2.CountextSelector
+ - auth.identity.username
+ when: ## Kuadrant API github.com/kuadrant/kuadrant-operator/api/v1beta2.WhenCondition
+ - selector: metadata.filter_metadata.envoy\.filters\.http\.ext_authz.identity.userid
+ operator: eq
+ value: alice
+```
diff --git a/examples/oas3/petstore-multiple-sec-requirements.yaml b/examples/oas3/petstore-multiple-sec-requirements.yaml
index 7afe0ff..91b2184 100644
--- a/examples/oas3/petstore-multiple-sec-requirements.yaml
+++ b/examples/oas3/petstore-multiple-sec-requirements.yaml
@@ -3,6 +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
servers:
- url: https://toplevel.example.io/v1
paths:
@@ -15,7 +24,7 @@ paths:
post: # API key
operationId: "postCat"
security:
- - petstore_api_key: []
+ - cat_api_key: []
responses:
405:
description: "invalid input"
@@ -23,17 +32,30 @@ paths:
get: # OIDC
operationId: "getDog"
security:
- - petstore_oidc:
+ - oidc:
- read:dogs
responses:
405:
description: "invalid input"
+ /snake:
+ get: # OIDC or API key
+ operationId: "getSnake"
+ security:
+ - oidc: ["read:snakes"]
+ - snakes_api_key: []
+ responses:
+ 405:
+ description: "invalid input"
components:
securitySchemes:
- petstore_api_key:
+ cat_api_key:
type: apiKey
name: api_key
in: header
- petstore_oidc:
+ oidc:
type: openIdConnect
- openIdConnectUrl: http://example.org/auth/realms/myrealm
+ openIdConnectUrl: https://example.com/.well-known/openid-configuration
+ snakes_api_key:
+ type: apiKey
+ name: snake_token
+ in: query
diff --git a/examples/oas3/petstore-with-oidc-kuadrant-extensions.yaml b/examples/oas3/petstore-with-oidc-kuadrant-extensions.yaml
new file mode 100644
index 0000000..cdcc0b8
--- /dev/null
+++ b/examples/oas3/petstore-with-oidc-kuadrant-extensions.yaml
@@ -0,0 +1,53 @@
+---
+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
+servers:
+ - url: https://example.io/api/v1
+paths:
+ /cat:
+ x-kuadrant: ## Path level Kuadrant Extension
+ backendRefs:
+ - name: petstore
+ port: 80
+ namespace: petstore
+ get: # Added to the route and public (not auth)
+ operationId: "getCat"
+ responses:
+ 405:
+ description: "invalid input"
+ post: # NOT added to the route
+ x-kuadrant: ## Operation level Kuadrant Extension
+ enable: false
+ operationId: "postCat"
+ responses:
+ 405:
+ description: "invalid input"
+ /dog:
+ get: # Added to the route and authenticated
+ x-kuadrant: ## Operation level Kuadrant Extension
+ backendRefs:
+ - name: petstore
+ port: 80
+ namespace: petstore
+ operationId: "getDog"
+ security:
+ - openIdConnect: []
+ responses:
+ 405:
+ description: "invalid input"
+components:
+ securitySchemes:
+ openIdConnect:
+ type: openIdConnect
+ openIdConnectUrl: https://example.com/.well-known/openid-configuration
diff --git a/examples/oas3/petstore-with-rate-limit-kuadrant-extensions.yaml b/examples/oas3/petstore-with-rate-limit-kuadrant-extensions.yaml
new file mode 100644
index 0000000..f6e5548
--- /dev/null
+++ b/examples/oas3/petstore-with-rate-limit-kuadrant-extensions.yaml
@@ -0,0 +1,70 @@
+---
+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
+servers:
+ - url: https://example.io/api/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: ## Operation level Kuadrant Extension
+ 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 and NOT rate limited
+ x-kuadrant: ## Operation level Kuadrant Extension
+ backendRefs:
+ - name: petstore
+ port: 80
+ namespace: petstore
+ operationId: "postDog"
+ responses:
+ 405:
+ description: "invalid input"
diff --git a/examples/oas3/petstore.yaml b/examples/oas3/petstore.yaml
index d141f96..1d5e3e2 100644
--- a/examples/oas3/petstore.yaml
+++ b/examples/oas3/petstore.yaml
@@ -1,5 +1,5 @@
---
-openapi: "3.0.0"
+openapi: "3.0.2"
info:
title: "Pet Store API"
version: "1.0.0"
diff --git a/examples/petstore/petstore.yaml b/examples/petstore/petstore.yaml
new file mode 100644
index 0000000..fd733a5
--- /dev/null
+++ b/examples/petstore/petstore.yaml
@@ -0,0 +1,39 @@
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: petstore
+ labels:
+ app: petstore
+spec:
+ selector:
+ matchLabels:
+ app: petstore
+ template:
+ metadata:
+ labels:
+ app: petstore
+ spec:
+ containers:
+ - name: petstore
+ image: quay.io/3scale/authorino:echo-api
+ env:
+ - name: PORT
+ value: "3000"
+ ports:
+ - containerPort: 3000
+ name: http
+ replicas: 1
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: petstore
+spec:
+ selector:
+ app: petstore
+ ports:
+ - name: http
+ port: 80
+ protocol: TCP
+ targetPort: 3000
diff --git a/go.mod b/go.mod
index b4c9f3d..fa79738 100644
--- a/go.mod
+++ b/go.mod
@@ -1,9 +1,9 @@
module github.com/kuadrant/kuadrantctl
-go 1.20
+go 1.21
require (
- github.com/getkin/kin-openapi v0.76.0
+ github.com/getkin/kin-openapi v0.120.0
github.com/kuadrant/kuadrant-operator v0.4.1
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.27.10
@@ -13,17 +13,20 @@ require (
k8s.io/apiextensions-apiserver v0.28.3
k8s.io/apimachinery v0.28.3
k8s.io/client-go v0.28.3
+ k8s.io/utils v0.0.0-20230726121419-3b25d923346b
sigs.k8s.io/controller-runtime v0.16.3
sigs.k8s.io/gateway-api v0.6.2
)
require (
+ github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
+ github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/elliotchance/orderedmap/v2 v2.2.0 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch/v5 v5.7.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
- github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/zapr v1.2.4 // indirect
github.com/go-openapi/jsonpointer v0.20.0 // indirect
@@ -38,17 +41,29 @@ require (
github.com/google/uuid v1.3.1 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
+ github.com/invopop/yaml v0.2.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
+ github.com/kuadrant/authorino v0.15.0 // indirect
github.com/kuadrant/authorino-operator v0.9.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
+ github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nxadm/tail v1.4.8 // indirect
+ github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
+ github.com/prometheus/client_golang v1.16.0 // indirect
+ github.com/prometheus/client_model v0.4.0 // indirect
+ github.com/prometheus/common v0.44.0 // indirect
+ github.com/prometheus/procfs v0.10.1 // indirect
github.com/sirupsen/logrus v1.9.2 // indirect
github.com/spf13/pflag v1.0.5 // indirect
+ github.com/tidwall/gjson v1.14.0 // indirect
+ github.com/tidwall/match v1.1.1 // indirect
+ github.com/tidwall/pretty v1.2.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
@@ -58,6 +73,7 @@ require (
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect
+ gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect
@@ -67,9 +83,9 @@ require (
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
istio.io/api v0.0.0-20230712174848-a2b2de508c88 // indirect
+ k8s.io/component-base v0.28.3 // indirect
k8s.io/klog/v2 v2.100.1 // indirect
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
- k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
diff --git a/go.sum b/go.sum
index 75f2101..661e0eb 100644
--- a/go.sum
+++ b/go.sum
@@ -1,43 +1,47 @@
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/elliotchance/orderedmap/v2 v2.2.0 h1:7/2iwO98kYT4XkOjA9mBEIwvi4KpGB4cyHeOFOnj4Vk=
+github.com/elliotchance/orderedmap/v2 v2.2.0/go.mod h1:85lZyVbpGaGvHvnKa7Qhx7zncAdBIBq6u56Hb1PRU5Q=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
+github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch/v5 v5.7.0 h1:nJqP7uwL84RJInrohHfW0Fx3awjbm8qZeFv0nW9SYGc=
github.com/evanphx/json-patch/v5 v5.7.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
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/getkin/kin-openapi v0.76.0 h1:j77zg3Ec+k+r+GA3d8hBoXpAc6KX9TbBPrwQGBIy2sY=
-github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
-github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/getkin/kin-openapi v0.120.0 h1:MqJcNJFrMDFNc07iwE8iFC5eT2k/NPUFDIpNeiZv8Jg=
+github.com/getkin/kin-openapi v0.120.0/go.mod h1:PCWw/lfBrJY4HcdqE3jj+QFkaFK8ABoqo7PvqVhXXqw=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA=
-github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
-github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
+github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
+github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
@@ -66,14 +70,16 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20221212185716-aee1124e3a93 h1:D5iJJZKAi0rU4e/5E58BkrnN+xeCDjAIqcm1GGxAGSI=
+github.com/google/pprof v0.0.0-20221212185716-aee1124e3a93/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
+github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -83,25 +89,30 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
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/kuadrant/authorino v0.15.0 h1:Xw/buh/wTINdL+IpLSxhlpet4hpleMxZzfx39c4VQng=
+github.com/kuadrant/authorino v0.15.0/go.mod h1:vXkHKrntn8DR7kt8a8Ohxq+2lgAD0jWivThoP+7ASew=
github.com/kuadrant/authorino-operator v0.9.0 h1:EV7zrYBNcd53HPQMivvTwe/+DIATTK7O4znJzh4xON8=
github.com/kuadrant/authorino-operator v0.9.0/go.mod h1:VkUqS4CHNiaHMrjSFQ5V71DN829kPnqT3FQxqlOntEI=
github.com/kuadrant/kuadrant-operator v0.4.1 h1:nGk7786goNzItxbIifmGWj6/Al8S7U+eT0fTcgEZphU=
github.com/kuadrant/kuadrant-operator v0.4.1/go.mod h1:iD+CMYKOfcpSts2JxscTlkeBgsusBwEhVsuJw832EAY=
github.com/kuadrant/limitador-operator v0.4.0 h1:HgJi7LuOsenCUMs2ACCfKMKsKpfHcqmmwVmqpci0hw4=
-github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/kuadrant/limitador-operator v0.4.0/go.mod h1:5fQo2XwxPr7bDObut9sK5sHCnK4hwAmTsTptaYvGfuc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
+github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
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/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
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/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
@@ -112,22 +123,30 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
+github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/operator-framework/api v0.19.0 h1:QU1CTJU+CufoeneA5rsNlP/uP96s8vDHWUYDFZTauzA=
github.com/operator-framework/api v0.19.0/go.mod h1:SCCslqke6AVOJ5JM+NqNE1CHuAgJLScsL66pnPaSMXs=
+github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
+github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
+github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
+github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
+github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
+github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y=
github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
@@ -145,6 +164,15 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w=
+github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
+github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
+github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
@@ -152,6 +180,7 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
+go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
@@ -184,6 +213,7 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY=
golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/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=
@@ -228,11 +258,13 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
+golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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=
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
+gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 h1:9NWlQfY2ePejTmfwUH1OWwmznFa+0kKcHGPDvcPza9M=
@@ -265,9 +297,11 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
+gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
istio.io/api v0.0.0-20230712174848-a2b2de508c88 h1:w7lSk+XcYNzGC5xtHBFvaV7QTBMQC5nM4l8xxFslGgk=
istio.io/api v0.0.0-20230712174848-a2b2de508c88/go.mod h1:owGDRg9uqMob8CN1gxaOzk6nJxnbT8wrP7PmggpJHHY=
k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM=
@@ -279,6 +313,7 @@ k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb
k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4=
k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo=
k8s.io/component-base v0.28.3 h1:rDy68eHKxq/80RiMb2Ld/tbH8uAE75JdCqJyi6lXMzI=
+k8s.io/component-base v0.28.3/go.mod h1:fDJ6vpVNSk6cRo5wmDa6eKIG7UlIQkaFmZN2fYgIUD8=
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
diff --git a/make/gateway-api.mk b/make/gateway-api.mk
index 81bd84e..e96f660 100644
--- a/make/gateway-api.mk
+++ b/make/gateway-api.mk
@@ -1,5 +1,9 @@
##@ Gateway API resources
+.PHONY: deploy-gateway
+deploy-gateway: kustomize ## Deploy Gateway API gateway
+ $(KUSTOMIZE) build config/gateway-api/gateway | kubectl apply -f -
+
.PHONY: gateway-api-install
gateway-api-install: kustomize ## Install Gateway API CRDs
$(KUSTOMIZE) build config/gateway-api | kubectl apply -f -
diff --git a/make/istio.mk b/make/istio.mk
index 9644f45..a958dd9 100644
--- a/make/istio.mk
+++ b/make/istio.mk
@@ -18,7 +18,7 @@ istioctl: $(ISTIOCTL) ## Download istioctl locally if necessary.
.PHONY: istio-install
istio-install: istioctl ## Install istio.
- $(ISTIOCTL) install --set profile=demo -y
+ $(ISTIOCTL) install -f utils/istio-operator.yaml -y
.PHONY: istio-uninstall
istio-uninstall: istioctl ## Uninstall istio.
diff --git a/make/kind.mk b/make/kind.mk
index 4c26b5b..12f9aab 100644
--- a/make/kind.mk
+++ b/make/kind.mk
@@ -3,12 +3,12 @@
## Targets to help install and use kind for development https://kind.sigs.k8s.io
-KIND_CLUSTER_NAME ?= kuadrant-local
+KIND_CLUSTER_NAME ?= kuadrantctl-local
.PHONY: kind-create-cluster
-kind-create-cluster: kind ## Create the "kuadrant-local" kind cluster.
+kind-create-cluster: kind ## Create the "kuadrantctl-local" kind cluster.
$(KIND) create cluster --name $(KIND_CLUSTER_NAME) --config utils/kind-cluster.yaml
.PHONY: kind-delete-cluster
-kind-delete-cluster: kind ## Delete the "kuadrant-local" kind cluster.
+kind-delete-cluster: kind ## Delete the "kuadrantctl-local" kind cluster.
- $(KIND) delete cluster --name $(KIND_CLUSTER_NAME)
diff --git a/make/lint.mk b/make/lint.mk
index 45842b0..c190494 100644
--- a/make/lint.mk
+++ b/make/lint.mk
@@ -1,7 +1,7 @@
GOLANGCI-LINT=$(PROJECT_PATH)/bin/golangci-lint
$(GOLANGCI-LINT):
mkdir -p $(PROJECT_PATH)/bin
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(PROJECT_PATH)/bin v1.41.1
+ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(PROJECT_PATH)/bin v1.55.2
.PHONY: golangci-lint
golangci-lint: $(GOLANGCI-LINT)
diff --git a/pkg/gatewayapi/http_route.go b/pkg/gatewayapi/http_route.go
index 4558a19..68c2ea4 100644
--- a/pkg/gatewayapi/http_route.go
+++ b/pkg/gatewayapi/http_route.go
@@ -2,62 +2,134 @@ package gatewayapi
import (
"github.com/getkin/kin-openapi/openapi3"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/utils/ptr"
gatewayapiv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
+
+ "github.com/kuadrant/kuadrantctl/pkg/utils"
)
-func HTTPRouteMatchesFromOAS(doc *openapi3.T) ([]gatewayapiv1beta1.HTTPRouteMatch, error) {
- httpRouteMatches := []gatewayapiv1beta1.HTTPRouteMatch{}
- pathMatchExactPath := gatewayapiv1beta1.PathMatchExact
+func HTTPRouteObjectMetaFromOAS(doc *openapi3.T) metav1.ObjectMeta {
+ if doc.Info == nil {
+ return metav1.ObjectMeta{}
+ }
- for path, pathItem := range doc.Paths {
+ kuadrantInfoExtension, err := utils.NewKuadrantOASInfoExtension(doc.Info)
+ if err != nil {
+ panic(err)
+ }
- headers := []gatewayapiv1beta1.HTTPHeaderMatch{}
- queryParams := []gatewayapiv1beta1.HTTPQueryParamMatch{}
- headers, queryParams = addRuleMatcherFromParams(pathItem.Parameters, headers, queryParams)
+ if kuadrantInfoExtension.Route == nil {
+ panic("info kuadrant extension route not found")
+ }
- for verb, operation := range pathItem.Operations() {
+ if kuadrantInfoExtension.Route.Name == nil {
+ panic("info kuadrant extension route name not found")
+ }
- headers, queryParams = addRuleMatcherFromParams(operation.Parameters, headers, queryParams)
-
- pathValue := path
- httpMethod := gatewayapiv1beta1.HTTPMethod(verb)
- httpRouteMatches = append(httpRouteMatches, gatewayapiv1beta1.HTTPRouteMatch{
- Method: &httpMethod,
- Path: &gatewayapiv1beta1.HTTPPathMatch{
- Type: &pathMatchExactPath,
- Value: &pathValue,
- },
- Headers: headers,
- QueryParams: queryParams,
- })
- }
+ om := metav1.ObjectMeta{
+ Name: *kuadrantInfoExtension.Route.Name,
+ Labels: kuadrantInfoExtension.Route.Labels,
}
- return httpRouteMatches, nil
+ if kuadrantInfoExtension.Route.Namespace != nil {
+ om.Namespace = *kuadrantInfoExtension.Route.Namespace
+ }
+
+ return om
}
-func addRuleMatcherFromParams(params openapi3.Parameters, headers []gatewayapiv1beta1.HTTPHeaderMatch, queryParams []gatewayapiv1beta1.HTTPQueryParamMatch) ([]gatewayapiv1beta1.HTTPHeaderMatch, []gatewayapiv1beta1.HTTPQueryParamMatch) {
- headerMatchType := gatewayapiv1beta1.HeaderMatchExact
- queryParamMatchExact := gatewayapiv1beta1.QueryParamMatchExact
+func HTTPRouteGatewayParentRefsFromOAS(doc *openapi3.T) []gatewayapiv1beta1.ParentReference {
+ if doc.Info == nil {
+ return nil
+ }
- for _, parameter := range params {
- if !parameter.Value.Required {
- continue
- }
+ kuadrantInfoExtension, err := utils.NewKuadrantOASInfoExtension(doc.Info)
+ if err != nil {
+ panic(err)
+ }
+
+ if kuadrantInfoExtension.Route == nil {
+ panic("info kuadrant extension route not found")
+ }
+
+ return kuadrantInfoExtension.Route.ParentRefs
+}
+
+func HTTPRouteHostnamesFromOAS(doc *openapi3.T) []gatewayapiv1beta1.Hostname {
+ if doc.Info == nil {
+ return nil
+ }
+
+ kuadrantInfoExtension, err := utils.NewKuadrantOASInfoExtension(doc.Info)
+ if err != nil {
+ panic(err)
+ }
- if parameter.Value.In == openapi3.ParameterInHeader {
- headers = append(headers, gatewayapiv1beta1.HTTPHeaderMatch{
- Type: &headerMatchType,
- Name: gatewayapiv1beta1.HTTPHeaderName(parameter.Value.Name),
- })
+ if kuadrantInfoExtension.Route == nil {
+ panic("info kuadrant extension route not found")
+ }
+
+ return kuadrantInfoExtension.Route.Hostnames
+}
+
+func HTTPRouteRulesFromOAS(doc *openapi3.T) []gatewayapiv1beta1.HTTPRouteRule {
+ // Current implementation, one rule per operation
+ // TODO(eguzki): consider about grouping operations as HTTPRouteMatch objects in fewer HTTPRouteRule objects
+ rules := make([]gatewayapiv1beta1.HTTPRouteRule, 0)
+
+ basePath, err := utils.BasePathFromOpenAPI(doc)
+ if err != nil {
+ panic(err)
+ }
+
+ // Paths
+ for path, pathItem := range doc.Paths {
+ kuadrantPathExtension, err := utils.NewKuadrantOASPathExtension(pathItem)
+ if err != nil {
+ panic(err)
}
- if parameter.Value.In == openapi3.ParameterInQuery {
- queryParams = append(queryParams, gatewayapiv1beta1.HTTPQueryParamMatch{
- Type: &queryParamMatchExact,
- Name: parameter.Value.Name,
- })
+
+ // Operations
+ for verb, operation := range pathItem.Operations() {
+ kuadrantOperationExtension, err := utils.NewKuadrantOASOperationExtension(operation)
+ if err != nil {
+ panic(err)
+ }
+
+ if ptr.Deref(kuadrantOperationExtension.Disable, kuadrantPathExtension.IsDisabled()) {
+ // not enabled for the operation
+ continue
+ }
+
+ // default backendrefs at the path level
+ backendRefs := kuadrantPathExtension.BackendRefs
+ if len(kuadrantOperationExtension.BackendRefs) > 0 {
+ backendRefs = kuadrantOperationExtension.BackendRefs
+ }
+
+ // default pathMatchType at the path level
+ pathMatchType := ptr.Deref(
+ kuadrantOperationExtension.PathMatchType,
+ kuadrantPathExtension.GetPathMatchType(),
+ )
+
+ rules = append(rules, buildHTTPRouteRule(basePath, path, pathItem, verb, operation, backendRefs, pathMatchType))
}
}
- return headers, queryParams
+ if len(rules) == 0 {
+ return nil
+ }
+
+ return rules
+}
+
+func buildHTTPRouteRule(basePath, path string, pathItem *openapi3.PathItem, verb string, op *openapi3.Operation, backendRefs []gatewayapiv1beta1.HTTPBackendRef, pathMatchType gatewayapiv1beta1.PathMatchType) gatewayapiv1beta1.HTTPRouteRule {
+ match := utils.OpenAPIMatcherFromOASOperations(basePath, path, pathItem, verb, op, pathMatchType)
+
+ return gatewayapiv1beta1.HTTPRouteRule{
+ BackendRefs: backendRefs,
+ Matches: []gatewayapiv1beta1.HTTPRouteMatch{match},
+ }
}
diff --git a/pkg/kuadrantapi/authpolicy.go b/pkg/kuadrantapi/authpolicy.go
new file mode 100644
index 0000000..0a87a46
--- /dev/null
+++ b/pkg/kuadrantapi/authpolicy.go
@@ -0,0 +1,254 @@
+package kuadrantapi
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ authorinoapi "github.com/kuadrant/authorino/api/v1beta2"
+ kuadrantapiv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/utils/ptr"
+ gatewayapiv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
+
+ "github.com/kuadrant/kuadrantctl/pkg/gatewayapi"
+ "github.com/kuadrant/kuadrantctl/pkg/utils"
+)
+
+const (
+ APIKeySecretLabel = "kuadrant.io/apikeys-by"
+)
+
+func AuthPolicyObjectMetaFromOAS(doc *openapi3.T) metav1.ObjectMeta {
+ return gatewayapi.HTTPRouteObjectMetaFromOAS(doc)
+}
+
+func buildAuthPolicyRouteSelectors(basePath, path string, pathItem *openapi3.PathItem, verb string, op *openapi3.Operation, pathMatchType gatewayapiv1beta1.PathMatchType) []kuadrantapiv1beta2.RouteSelector {
+ match := utils.OpenAPIMatcherFromOASOperations(basePath, path, pathItem, verb, op, pathMatchType)
+
+ return []kuadrantapiv1beta2.RouteSelector{
+ {
+ Matches: []gatewayapiv1beta1.HTTPRouteMatch{match},
+ },
+ }
+}
+
+func AuthPolicyTopRouteSelectorsFromOAS(doc *openapi3.T) []kuadrantapiv1beta2.RouteSelector {
+ routeSelectors := make([]kuadrantapiv1beta2.RouteSelector, 0)
+
+ basePath, err := utils.BasePathFromOpenAPI(doc)
+ if err != nil {
+ panic(err)
+ }
+
+ for path, pathItem := range doc.Paths {
+ kuadrantPathExtension, err := utils.NewKuadrantOASPathExtension(pathItem)
+ if err != nil {
+ panic(err)
+ }
+
+ // Operations
+ for verb, operation := range pathItem.Operations() {
+ kuadrantOperationExtension, err := utils.NewKuadrantOASOperationExtension(operation)
+ if err != nil {
+ panic(err)
+ }
+
+ if ptr.Deref(kuadrantOperationExtension.Disable, kuadrantPathExtension.IsDisabled()) {
+ // not enabled for the operation
+ //fmt.Printf("OUT not enabled: path: %s, method: %s\n", path, verb)
+ continue
+ }
+
+ // Get operation level security requirements or fallback to global security requirements
+ secRequirements := ptr.Deref(operation.Security, doc.Security)
+
+ // Top RouteSelectors define the matching rules to call external auth service
+ // group together any routes that has at least one security requirement
+ if len(secRequirements) == 0 {
+ // no security
+ continue
+ }
+
+ // default pathMatchType at the path level
+ pathMatchType := ptr.Deref(
+ kuadrantOperationExtension.PathMatchType,
+ kuadrantPathExtension.GetPathMatchType(),
+ )
+
+ routeSelectors = append(routeSelectors, buildAuthPolicyRouteSelectors(basePath, path, pathItem, verb, operation, pathMatchType)...)
+ }
+ }
+
+ if len(routeSelectors) == 0 {
+ return nil
+ }
+
+ return routeSelectors
+}
+
+func AuthPolicyAuthenticationSchemeFromOAS(doc *openapi3.T) map[string]kuadrantapiv1beta2.AuthenticationSpec {
+ authentication := make(map[string]kuadrantapiv1beta2.AuthenticationSpec)
+
+ basePath, err := utils.BasePathFromOpenAPI(doc)
+ if err != nil {
+ panic(err)
+ }
+
+ // Paths
+ for path, pathItem := range doc.Paths {
+ kuadrantPathExtension, err := utils.NewKuadrantOASPathExtension(pathItem)
+ if err != nil {
+ panic(err)
+ }
+
+ // Operations
+ for verb, operation := range pathItem.Operations() {
+ kuadrantOperationExtension, err := utils.NewKuadrantOASOperationExtension(operation)
+ if err != nil {
+ panic(err)
+ }
+
+ if ptr.Deref(kuadrantOperationExtension.Disable, kuadrantPathExtension.IsDisabled()) {
+ // not enabled for the operation
+ //fmt.Printf("OUT not enabled: path: %s, method: %s\n", path, verb)
+ continue
+ }
+
+ // Get operation level security requirements or fallback to global security requirements
+ secRequirements := ptr.Deref(operation.Security, doc.Security)
+
+ if len(secRequirements) == 0 {
+ // no security
+ continue
+ }
+
+ // default pathMatchType at the path level
+ pathMatchType := ptr.Deref(
+ kuadrantOperationExtension.PathMatchType,
+ kuadrantPathExtension.GetPathMatchType(),
+ )
+
+ operationAuthentication := buildOperationAuthentication(doc, basePath, path, pathItem, verb, operation, pathMatchType, secRequirements)
+
+ // Aggregate auth methods per operation
+ authentication = utils.MergeMaps(authentication, operationAuthentication)
+ }
+ }
+
+ if len(authentication) == 0 {
+ return nil
+ }
+
+ return authentication
+}
+
+func buildOperationAuthentication(doc *openapi3.T, basePath, path string, pathItem *openapi3.PathItem, verb string, op *openapi3.Operation, pathMatchType gatewayapiv1beta1.PathMatchType, secRequirements openapi3.SecurityRequirements) map[string]kuadrantapiv1beta2.AuthenticationSpec {
+ // OpenAPI supports as security requirement to have multiple security schemes and ALL
+ // of the must be satisfied.
+ // From https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#security-requirement-object
+ // Kuadrant does not support it yet: https://github.com/Kuadrant/authorino/issues/112
+ // not supported (AND'ed)
+ // security:
+ // - petstore_api_key: []
+ // petstore_oidc: []
+ // supported (OR'ed)
+ // security:
+ // - petstore_api_key: []
+ // - petstore_oidc: []
+
+ opAuth := make(map[string]kuadrantapiv1beta2.AuthenticationSpec, 0)
+ for _, secReq := range secRequirements {
+ if len(secReq) > 1 {
+ panic(errors.New("multiple schemes that require ALL must be satisfied, currently not supported"))
+ }
+
+ extractSecReqItemName := func(sr openapi3.SecurityRequirement) string {
+ for secReqItemName := range sr {
+ return secReqItemName
+ }
+
+ return ""
+ }
+
+ secReqItemName := extractSecReqItemName(secReq)
+
+ secScheme, ok := doc.Components.SecuritySchemes[secReqItemName]
+ if !ok {
+ // should never happen. OpenAPI validation should detect this issue
+ continue
+ }
+
+ if secScheme == nil || secScheme.Value == nil {
+ continue
+ }
+
+ authName := fmt.Sprintf("%s_%s", utils.OpenAPIOperationName(path, verb, op), secReqItemName)
+
+ // Ref https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#fixed-fields-23
+ switch secScheme.Value.Type {
+ case "openIdConnect":
+ opAuth[authName] = openIDAuthenticationSpec(basePath, path, pathItem, verb, op, pathMatchType, *secScheme.Value)
+ case "apiKey":
+ opAuth[authName] = apiKeyAuthenticationSpec(basePath, path, pathItem, verb, op, pathMatchType, secReqItemName, *secScheme.Value)
+ }
+ }
+
+ if len(opAuth) == 0 {
+ return nil
+ }
+
+ return opAuth
+}
+
+func apiKeyAuthenticationSpec(basePath, path string, pathItem *openapi3.PathItem, verb string, op *openapi3.Operation, pathMatchType gatewayapiv1beta1.PathMatchType, secSchemeName string, secScheme openapi3.SecurityScheme) kuadrantapiv1beta2.AuthenticationSpec {
+ // From https://github.com/Kuadrant/kuadrantctl/pull/46#issuecomment-1830278191
+ // secScheme.In is required
+ // secScheme.Name is required
+ credentials := authorinoapi.Credentials{}
+ switch secScheme.In {
+ case "query":
+ credentials.QueryString = &authorinoapi.Named{Name: secScheme.Name}
+ case "header":
+ credentials.CustomHeader = &authorinoapi.CustomHeader{
+ Named: authorinoapi.Named{Name: secScheme.Name},
+ }
+ case "cookie":
+ credentials.Cookie = &authorinoapi.Named{Name: secScheme.Name}
+ }
+
+ return kuadrantapiv1beta2.AuthenticationSpec{
+ CommonAuthRuleSpec: kuadrantapiv1beta2.CommonAuthRuleSpec{
+ RouteSelectors: buildAuthPolicyRouteSelectors(basePath, path, pathItem, verb, op, pathMatchType),
+ },
+ AuthenticationSpec: authorinoapi.AuthenticationSpec{
+ Credentials: credentials,
+ AuthenticationMethodSpec: authorinoapi.AuthenticationMethodSpec{
+ ApiKey: &authorinoapi.ApiKeyAuthenticationSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{
+ // label selector be like
+ // kuadrant.io/apikeys-by: ${SecuritySchemeName}
+ APIKeySecretLabel: secSchemeName,
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func openIDAuthenticationSpec(basePath, path string, pathItem *openapi3.PathItem, verb string, op *openapi3.Operation, pathMatchType gatewayapiv1beta1.PathMatchType, secScheme openapi3.SecurityScheme) kuadrantapiv1beta2.AuthenticationSpec {
+ return kuadrantapiv1beta2.AuthenticationSpec{
+ CommonAuthRuleSpec: kuadrantapiv1beta2.CommonAuthRuleSpec{
+ RouteSelectors: buildAuthPolicyRouteSelectors(basePath, path, pathItem, verb, op, pathMatchType),
+ },
+ AuthenticationSpec: authorinoapi.AuthenticationSpec{
+ AuthenticationMethodSpec: authorinoapi.AuthenticationMethodSpec{
+ Jwt: &authorinoapi.JwtAuthenticationSpec{
+ IssuerUrl: secScheme.OpenIdConnectUrl,
+ },
+ },
+ },
+ }
+}
diff --git a/pkg/kuadrantapi/rate_limit_policy.go b/pkg/kuadrantapi/rate_limit_policy.go
new file mode 100644
index 0000000..2509574
--- /dev/null
+++ b/pkg/kuadrantapi/rate_limit_policy.go
@@ -0,0 +1,93 @@
+package kuadrantapi
+
+import (
+ "github.com/getkin/kin-openapi/openapi3"
+ kuadrantapiv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/utils/ptr"
+ gatewayapiv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
+
+ "github.com/kuadrant/kuadrantctl/pkg/gatewayapi"
+ "github.com/kuadrant/kuadrantctl/pkg/utils"
+)
+
+func RateLimitPolicyObjectMetaFromOAS(doc *openapi3.T) metav1.ObjectMeta {
+ return gatewayapi.HTTPRouteObjectMetaFromOAS(doc)
+}
+
+func RateLimitPolicyLimitsFromOAS(doc *openapi3.T) map[string]kuadrantapiv1beta2.Limit {
+ // Current implementation, one limit per operation
+ // TODO(eguzki): consider about grouping operations in fewer RLP limits
+
+ limits := make(map[string]kuadrantapiv1beta2.Limit)
+
+ basePath, err := utils.BasePathFromOpenAPI(doc)
+ if err != nil {
+ panic(err)
+ }
+
+ // Paths
+ for path, pathItem := range doc.Paths {
+ kuadrantPathExtension, err := utils.NewKuadrantOASPathExtension(pathItem)
+ if err != nil {
+ panic(err)
+ }
+
+ // Operations
+ for verb, operation := range pathItem.Operations() {
+ kuadrantOperationExtension, err := utils.NewKuadrantOASOperationExtension(operation)
+ if err != nil {
+ panic(err)
+ }
+
+ if ptr.Deref(kuadrantOperationExtension.Disable, kuadrantPathExtension.IsDisabled()) {
+ // not enabled for the operation
+ //fmt.Printf("OUT not enabled: path: %s, method: %s\n", path, verb)
+ continue
+ }
+
+ // default backendrefs at the path level
+ rateLimit := kuadrantPathExtension.RateLimit
+ if kuadrantOperationExtension.RateLimit != nil {
+ rateLimit = kuadrantOperationExtension.RateLimit
+ }
+
+ if rateLimit == nil {
+ // no rate limit defined for this operation
+ //fmt.Printf("OUT no rate limit defined: path: %s, method: %s\n", path, verb)
+ continue
+ }
+
+ // default pathMatchType at the path level
+ pathMatchType := ptr.Deref(
+ kuadrantOperationExtension.PathMatchType,
+ kuadrantPathExtension.GetPathMatchType(),
+ )
+
+ limitName := utils.OpenAPIOperationName(path, verb, operation)
+
+ limits[limitName] = kuadrantapiv1beta2.Limit{
+ RouteSelectors: buildLimitRouteSelectors(basePath, path, pathItem, verb, operation, pathMatchType),
+ When: rateLimit.When,
+ Counters: rateLimit.Counters,
+ Rates: rateLimit.Rates,
+ }
+ }
+ }
+
+ if len(limits) == 0 {
+ return nil
+ }
+
+ return limits
+}
+
+func buildLimitRouteSelectors(basePath, path string, pathItem *openapi3.PathItem, verb string, op *openapi3.Operation, pathMatchType gatewayapiv1beta1.PathMatchType) []kuadrantapiv1beta2.RouteSelector {
+ match := utils.OpenAPIMatcherFromOASOperations(basePath, path, pathItem, verb, op, pathMatchType)
+
+ return []kuadrantapiv1beta2.RouteSelector{
+ {
+ Matches: []gatewayapiv1beta1.HTTPRouteMatch{match},
+ },
+ }
+}
diff --git a/pkg/utils/external_resource_reader.go b/pkg/utils/external_resource_reader.go
index 6fdbc94..43dd6bf 100644
--- a/pkg/utils/external_resource_reader.go
+++ b/pkg/utils/external_resource_reader.go
@@ -16,17 +16,17 @@ limitations under the License.
package utils
import (
- "io/ioutil"
+ "io"
"os"
)
// ReadExternalResource reads data streams from external resources. Currently implemented:
-// - '-' for STDIN
+// - '@' for STDIN
// - URLs (HTTP[S])
// - Files
func ReadExternalResource(resource string) ([]byte, error) {
- if resource == "-" {
- return ioutil.ReadAll(os.Stdin)
+ if resource == "@" {
+ return io.ReadAll(os.Stdin)
}
if url, isURL := ParseURL(resource); isURL {
@@ -34,5 +34,5 @@ func ReadExternalResource(resource string) ([]byte, error) {
}
// Defaulting to filepath
- return ioutil.ReadFile(resource)
+ return os.ReadFile(resource)
}
diff --git a/pkg/utils/http_utils.go b/pkg/utils/http_utils.go
index 4a90cd7..9d2195c 100644
--- a/pkg/utils/http_utils.go
+++ b/pkg/utils/http_utils.go
@@ -16,7 +16,7 @@ limitations under the License.
package utils
import (
- "io/ioutil"
+ "io"
"net/http"
"net/url"
)
@@ -32,7 +32,7 @@ func ReadURL(location *url.URL) ([]byte, error) {
if err != nil {
return nil, err
}
- data, err := ioutil.ReadAll(resp.Body)
+ data, err := io.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
return nil, err
diff --git a/pkg/utils/k8s_utils.go b/pkg/utils/k8s_utils.go
index 075b9d4..80e87d6 100644
--- a/pkg/utils/k8s_utils.go
+++ b/pkg/utils/k8s_utils.go
@@ -123,9 +123,9 @@ func IsDeploymentAvailable(dc *appsv1.Deployment) bool {
return false
}
-func CheckDeploymentAvailable(k8sClient client.Client, key types.NamespacedName) (bool, error) {
+func CheckDeploymentAvailable(ctx context.Context, k8sClient client.Client, key types.NamespacedName) (bool, error) {
existingDeployment := &appsv1.Deployment{}
- err := k8sClient.Get(context.Background(), key, existingDeployment)
+ err := k8sClient.Get(ctx, key, existingDeployment)
if err != nil {
if apierrors.IsNotFound(err) {
logf.Log.Info("Deployment not available", "name", key.Name)
diff --git a/pkg/utils/kuadrant_oas_extension_types.go b/pkg/utils/kuadrant_oas_extension_types.go
new file mode 100644
index 0000000..699fef1
--- /dev/null
+++ b/pkg/utils/kuadrant_oas_extension_types.go
@@ -0,0 +1,110 @@
+package utils
+
+import (
+ "encoding/json"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ kuadrantapiv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2"
+ "k8s.io/utils/ptr"
+ gatewayapiv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
+)
+
+type RouteObject struct {
+ Name *string `json:"name,omitempty"`
+ Namespace *string `json:"namespace,omitempty"`
+ Hostnames []gatewayapiv1beta1.Hostname `json:"hostnames,omitempty"`
+ ParentRefs []gatewayapiv1beta1.ParentReference `json:"parentRefs,omitempty"`
+ Labels map[string]string `json:"labels,omitempty"`
+}
+
+type KuadrantOASInfoExtension struct {
+ Route *RouteObject `json:"route,omitempty"`
+}
+
+func NewKuadrantOASInfoExtension(info *openapi3.Info) (*KuadrantOASInfoExtension, error) {
+ type KuadrantOASInfoObject struct {
+ // Kuadrant extension
+ Kuadrant *KuadrantOASInfoExtension `json:"x-kuadrant,omitempty"`
+ }
+
+ data, err := info.MarshalJSON()
+ if err != nil {
+ return nil, err
+ }
+
+ var x KuadrantOASInfoObject
+ if err := json.Unmarshal(data, &x); err != nil {
+ return nil, err
+ }
+
+ return x.Kuadrant, nil
+}
+
+type KuadrantRateLimitExtension struct {
+ When []kuadrantapiv1beta2.WhenCondition `json:"when,omitempty"`
+
+ Counters []kuadrantapiv1beta2.ContextSelector `json:"counters,omitempty"`
+
+ Rates []kuadrantapiv1beta2.Rate `json:"rates,omitempty"`
+}
+
+type KuadrantOASPathExtension struct {
+ Disable *bool `json:"disable,omitempty"`
+ PathMatchType *gatewayapiv1beta1.PathMatchType `json:"pathMatchType,omitempty"`
+ BackendRefs []gatewayapiv1beta1.HTTPBackendRef `json:"backendRefs,omitempty"`
+ RateLimit *KuadrantRateLimitExtension `json:"rate_limit,omitempty"`
+}
+
+func (k *KuadrantOASPathExtension) IsDisabled() bool {
+ // Set default
+ return ptr.Deref(k.Disable, false)
+}
+
+func (k *KuadrantOASPathExtension) GetPathMatchType() gatewayapiv1beta1.PathMatchType {
+ // Set default
+ return ptr.Deref(k.PathMatchType, gatewayapiv1beta1.PathMatchExact)
+}
+
+func NewKuadrantOASPathExtension(pathItem *openapi3.PathItem) (*KuadrantOASPathExtension, error) {
+ type KuadrantOASPathObject struct {
+ // Kuadrant extension
+ Kuadrant *KuadrantOASPathExtension `json:"x-kuadrant,omitempty"`
+ }
+
+ data, err := pathItem.MarshalJSON()
+ if err != nil {
+ return nil, err
+ }
+
+ var x KuadrantOASPathObject
+ if err := json.Unmarshal(data, &x); err != nil {
+ return nil, err
+ }
+
+ kuadrantExtension := ptr.Deref(x.Kuadrant, KuadrantOASPathExtension{})
+
+ return &kuadrantExtension, nil
+}
+
+type KuadrantOASOperationExtension KuadrantOASPathExtension
+
+func NewKuadrantOASOperationExtension(operation *openapi3.Operation) (*KuadrantOASOperationExtension, error) {
+ type KuadrantOASOperationObject struct {
+ // Kuadrant extension
+ Kuadrant *KuadrantOASOperationExtension `json:"x-kuadrant,omitempty"`
+ }
+
+ data, err := operation.MarshalJSON()
+ if err != nil {
+ return nil, err
+ }
+
+ var x KuadrantOASOperationObject
+ if err := json.Unmarshal(data, &x); err != nil {
+ return nil, err
+ }
+
+ kuadrantExtension := ptr.Deref(x.Kuadrant, KuadrantOASOperationExtension{})
+
+ return &kuadrantExtension, nil
+}
diff --git a/pkg/utils/maps.go b/pkg/utils/maps.go
new file mode 100644
index 0000000..c423dc4
--- /dev/null
+++ b/pkg/utils/maps.go
@@ -0,0 +1,12 @@
+package utils
+
+func MergeMaps[K comparable, V any](MyMap1 map[K]V, MyMap2 map[K]V) map[K]V {
+ merged := make(map[K]V)
+ for key, val := range MyMap1 {
+ merged[key] = val
+ }
+ for key, val := range MyMap2 {
+ merged[key] = val
+ }
+ return merged
+}
diff --git a/pkg/utils/oas3.go b/pkg/utils/oas3.go
deleted file mode 100644
index a9d0fa2..0000000
--- a/pkg/utils/oas3.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package utils
-
-import (
- "fmt"
- "regexp"
- "strings"
-
- "github.com/getkin/kin-openapi/openapi3"
- "k8s.io/apimachinery/pkg/util/validation"
-)
-
-var (
- // NonAlphanumRegexp not alphanumeric
- NonAlphanumRegexp = regexp.MustCompile(`[^0-9A-Za-z]`)
-)
-
-func K8sNameFromOpenAPITitle(obj *openapi3.T) (string, error) {
- openapiTitle := obj.Info.Title
- openapiTitleToLower := strings.ToLower(openapiTitle)
- objName := NonAlphanumRegexp.ReplaceAllString(openapiTitleToLower, "")
-
- // DNS Subdomain Names
- // If the name would be part of some label, validation would be DNS Label Names (validation.IsDNS1123Label)
- // https://kubernetes.io/docs/concepts/overview/working-with-objects/names/
- errStrings := validation.IsDNS1123Subdomain(objName)
- if len(errStrings) > 0 {
- errStr := strings.Join(errStrings, ",")
- return "", fmt.Errorf("k8s name from OAS not valid: %s", errStr)
- }
- return objName, nil
-}
-
-func ValidateOAS3(docRaw []byte) error {
- openapiLoader := openapi3.NewLoader()
- doc, err := openapiLoader.LoadFromData(docRaw)
- if err != nil {
- return err
- }
-
- err = doc.Validate(openapiLoader.Context)
- if err != nil {
- return fmt.Errorf("OpenAPI validation error: %w", err)
- }
-
- return nil
-}
-
-func OpenAPIOperationSecRequirements(oasDoc *openapi3.T, operation *openapi3.Operation) *openapi3.SecurityRequirements {
- if operation.Security == nil {
- return &oasDoc.Security
- }
- return operation.Security
-}
diff --git a/pkg/utils/oas_utils.go b/pkg/utils/oas_utils.go
new file mode 100644
index 0000000..46c55c1
--- /dev/null
+++ b/pkg/utils/oas_utils.go
@@ -0,0 +1,193 @@
+package utils
+
+import (
+ "bytes"
+ "fmt"
+ "html/template"
+ "net/url"
+ "regexp"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ gatewayapiv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
+)
+
+var (
+ // NonWordCharRegexp not word characters (== [^0-9A-Za-z_])
+ NonWordCharRegexp = regexp.MustCompile(`\W`)
+ // TemplateRegexp used to render openapi server URLs
+ TemplateRegexp = regexp.MustCompile(`{([\w]+)}`)
+ // LastSlashRegexp matches the last slash
+ LastSlashRegexp = regexp.MustCompile(`/$`)
+)
+
+func FirstServerFromOpenAPI(obj *openapi3.T) *openapi3.Server {
+ if obj == nil {
+ return nil
+ }
+
+ // take only first server
+ // From https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md
+ // If the servers property is not provided, or is an empty array, the default value would be a Server Object with a url value of /.
+ server := &openapi3.Server{
+ URL: `/`,
+ Variables: map[string]*openapi3.ServerVariable{},
+ }
+
+ // Current constraint: only read the first item when there are multiple servers
+ // Maybe this should be user provided setting
+ if len(obj.Servers) > 0 {
+ server = obj.Servers[0]
+ }
+
+ return server
+}
+
+func RenderOpenAPIServerURLStr(server *openapi3.Server) (string, error) {
+ if server == nil {
+ return "", nil
+ }
+
+ data := &struct {
+ Data map[string]string
+ }{
+ map[string]string{},
+ }
+
+ for variableName, variable := range server.Variables {
+ data.Data[variableName] = variable.Default
+ }
+
+ urlTemplate := TemplateRegexp.ReplaceAllString(server.URL, `{{ index .Data "$1" }}`)
+
+ tObj, err := template.New(server.URL).Parse(urlTemplate)
+ if err != nil {
+ return "", err
+ }
+
+ var tpl bytes.Buffer
+ err = tObj.Execute(&tpl, data)
+ if err != nil {
+ return "", err
+ }
+
+ return tpl.String(), nil
+}
+
+func RenderOpenAPIServerURL(server *openapi3.Server) (*url.URL, error) {
+ serverURLStr, err := RenderOpenAPIServerURLStr(server)
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(serverURLStr)
+ if err != nil {
+ return nil, err
+ }
+
+ return serverURL, nil
+}
+
+func BasePathFromOpenAPI(obj *openapi3.T) (string, error) {
+ server := FirstServerFromOpenAPI(obj)
+ serverURL, err := RenderOpenAPIServerURL(server)
+ if err != nil {
+ return "", err
+ }
+
+ return serverURL.Path, nil
+}
+
+func OpenAPIMatcherFromOASOperations(basePath, path string, pathItem *openapi3.PathItem, verb string, op *openapi3.Operation, pathMatchType gatewayapiv1beta1.PathMatchType) gatewayapiv1beta1.HTTPRouteMatch {
+ // remove the last slash of the Base Path
+ sanitizedBasePath := LastSlashRegexp.ReplaceAllString(basePath, "")
+
+ // According OAS 3.0: path MUST begin with a slash
+ matchPath := fmt.Sprintf("%s%s", sanitizedBasePath, path)
+
+ pathHeadersMatch := headersMatchFromParams(pathItem.Parameters)
+ operationHeadersMatch := headersMatchFromParams(op.Parameters)
+
+ // default headersMatch at the path level
+ headersMatch := pathHeadersMatch
+ if len(operationHeadersMatch) > 0 {
+ headersMatch = operationHeadersMatch
+ }
+
+ pathQueryParamsMatch := queryParamsMatchFromParams(pathItem.Parameters)
+ operationQueryParamsMatch := queryParamsMatchFromParams(op.Parameters)
+
+ // default queryParams at the path level
+ queryParams := pathQueryParamsMatch
+ if len(operationQueryParamsMatch) > 0 {
+ queryParams = operationQueryParamsMatch
+ }
+
+ return gatewayapiv1beta1.HTTPRouteMatch{
+ Method: &[]gatewayapiv1beta1.HTTPMethod{gatewayapiv1beta1.HTTPMethod(verb)}[0],
+ Path: &gatewayapiv1beta1.HTTPPathMatch{
+ Type: &pathMatchType,
+ Value: &[]string{matchPath}[0],
+ },
+ Headers: headersMatch,
+ QueryParams: queryParams,
+ }
+}
+
+func headersMatchFromParams(params openapi3.Parameters) []gatewayapiv1beta1.HTTPHeaderMatch {
+ matches := make([]gatewayapiv1beta1.HTTPHeaderMatch, 0)
+
+ for _, parameter := range params {
+ if !parameter.Value.Required {
+ continue
+ }
+
+ if parameter.Value.In == openapi3.ParameterInHeader {
+ matches = append(matches, gatewayapiv1beta1.HTTPHeaderMatch{
+ Type: &[]gatewayapiv1beta1.HeaderMatchType{gatewayapiv1beta1.HeaderMatchExact}[0],
+ Name: gatewayapiv1beta1.HTTPHeaderName(parameter.Value.Name),
+ })
+ }
+ }
+
+ if len(matches) == 0 {
+ return nil
+ }
+
+ return matches
+}
+
+func queryParamsMatchFromParams(params openapi3.Parameters) []gatewayapiv1beta1.HTTPQueryParamMatch {
+ matches := make([]gatewayapiv1beta1.HTTPQueryParamMatch, 0)
+
+ for _, parameter := range params {
+ if !parameter.Value.Required {
+ continue
+ }
+
+ if parameter.Value.In == openapi3.ParameterInQuery {
+ matches = append(matches, gatewayapiv1beta1.HTTPQueryParamMatch{
+ Type: &[]gatewayapiv1beta1.QueryParamMatchType{gatewayapiv1beta1.QueryParamMatchExact}[0],
+ Name: parameter.Value.Name,
+ })
+ }
+ }
+
+ if len(matches) == 0 {
+ return nil
+ }
+
+ return matches
+
+}
+
+func OpenAPIOperationName(path, opVerb string, op *openapi3.Operation) string {
+ sanitizedPath := NonWordCharRegexp.ReplaceAllString(path, "")
+
+ name := fmt.Sprintf("%s%s", opVerb, sanitizedPath)
+
+ if op.OperationID != "" {
+ name = op.OperationID
+ }
+
+ return name
+}
diff --git a/pkg/utils/utils.coverprofile b/pkg/utils/utils.coverprofile
deleted file mode 100644
index dbcac2a..0000000
--- a/pkg/utils/utils.coverprofile
+++ /dev/null
@@ -1,68 +0,0 @@
-mode: atomic
-github.com/kuadrant/kuadrantctl/pkg/utils/external_resource_reader.go:27.60,28.21 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/external_resource_reader.go:28.21,30.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/external_resource_reader.go:32.2,32.45 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/external_resource_reader.go:32.45,34.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/external_resource_reader.go:37.2,37.34 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/http_utils.go:25.44,28.2 2 9
-github.com/kuadrant/kuadrantctl/pkg/utils/http_utils.go:30.49,32.16 2 0
-github.com/kuadrant/kuadrantctl/pkg/utils/http_utils.go:32.16,34.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/http_utils.go:35.2,37.16 3 0
-github.com/kuadrant/kuadrantctl/pkg/utils/http_utils.go:37.16,39.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/http_utils.go:40.2,40.18 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:32.81,34.9 2 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:34.9,36.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:38.2,40.16 3 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:40.16,42.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:44.2,44.37 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:44.37,46.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:49.2,51.9 3 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:51.9,53.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:54.2,55.16 2 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:55.16,57.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:59.2,62.16 3 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:62.16,64.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:66.2,69.9 3 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:69.9,71.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:73.2,75.12 3 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:78.77,80.9 2 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:80.9,82.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:83.2,87.16 4 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:87.16,88.37 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:88.37,91.4 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:91.9,93.4 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:95.2,95.12 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:98.73,100.9 2 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:100.9,102.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:103.2,107.46 4 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:107.46,110.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:111.2,111.12 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:116.56,118.43 2 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:118.43,119.99 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:119.99,121.4 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:123.2,123.14 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:126.96,129.16 3 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:129.16,130.32 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:130.32,133.4 2 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:135.3,135.20 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:138.2,138.48 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:138.48,143.3 2 0
-github.com/kuadrant/kuadrantctl/pkg/utils/k8s_utils.go:145.2,146.18 2 0
-github.com/kuadrant/kuadrantctl/pkg/utils/oas3.go:17.63,26.25 5 0
-github.com/kuadrant/kuadrantctl/pkg/utils/oas3.go:26.25,29.3 2 0
-github.com/kuadrant/kuadrantctl/pkg/utils/oas3.go:30.2,30.21 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/oas3.go:33.40,36.16 3 0
-github.com/kuadrant/kuadrantctl/pkg/utils/oas3.go:36.16,38.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/oas3.go:40.2,41.16 2 0
-github.com/kuadrant/kuadrantctl/pkg/utils/oas3.go:41.16,43.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/oas3.go:45.2,45.12 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/oas3.go:48.120,49.31 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/oas3.go:49.31,51.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/oas3.go:52.2,52.27 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/scheme.go:10.26,12.16 2 0
-github.com/kuadrant/kuadrantctl/pkg/utils/scheme.go:12.16,14.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/scheme.go:16.2,17.16 2 0
-github.com/kuadrant/kuadrantctl/pkg/utils/scheme.go:17.16,19.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/scheme.go:21.2,22.16 2 0
-github.com/kuadrant/kuadrantctl/pkg/utils/scheme.go:22.16,24.3 1 0
-github.com/kuadrant/kuadrantctl/pkg/utils/scheme.go:26.2,26.12 1 0
diff --git a/utils/istio-operator.yaml b/utils/istio-operator.yaml
new file mode 100644
index 0000000..05db21c
--- /dev/null
+++ b/utils/istio-operator.yaml
@@ -0,0 +1,53 @@
+---
+apiVersion: install.istio.io/v1alpha1
+kind: IstioOperator
+spec:
+ profile: default
+ namespace: istio-system
+ components:
+ base:
+ enabled: true
+ cni:
+ enabled: false
+ egressGateways:
+ - enabled: false
+ name: istio-egressgateway
+ ingressGateways:
+ - enabled: true
+ name: istio-ingressgateway
+ k8s:
+ service:
+ type: NodePort
+ ports:
+ - name: status-port
+ port: 15021
+ protocol: TCP
+ targetPort: 15021
+ - name: http2
+ port: 80
+ protocol: TCP
+ targetPort: 8080
+ nodePort: 30950
+ - name: https
+ port: 443
+ protocol: TCP
+ targetPort: 8443
+ nodePort: 30951
+ resources:
+ requests:
+ cpu: "0"
+ pilot:
+ enabled: true
+ k8s:
+ resources:
+ requests:
+ cpu: "0"
+ values:
+ pilot:
+ autoscaleEnabled: false
+ gateways:
+ istio-ingressgateway:
+ type: ClusterIP
+ autoscaleEnabled: false
+ global:
+ istioNamespace: istio-system
diff --git a/utils/kind-cluster.yaml b/utils/kind-cluster.yaml
index 8e16566..a395098 100644
--- a/utils/kind-cluster.yaml
+++ b/utils/kind-cluster.yaml
@@ -5,3 +5,9 @@ nodes:
- role: control-plane
# port forward 80 on the host to 80 on this node
image: kindest/node:v1.27.3
+ # port forward 80 on the host to 80 on this node
+ extraPortMappings:
+ - containerPort: 30950
+ hostPort: 9080
+ - containerPort: 30951
+ hostPort: 9443