diff --git a/.github/workflows/building.yaml b/.github/workflows/building.yaml index 5cd637a..e878f48 100644 --- a/.github/workflows/building.yaml +++ b/.github/workflows/building.yaml @@ -21,10 +21,10 @@ jobs: name: Build manager runs-on: ubuntu-latest steps: - - name: Set up Go 1.16.x + - name: Set up Go 1.17.x uses: actions/setup-go@v2 with: - go-version: 1.16.x + go-version: 1.17.x id: go - name: Check out code uses: actions/checkout@v2 @@ -36,10 +36,10 @@ jobs: name: Build image runs-on: ubuntu-latest steps: - - name: Set up Go 1.16.x + - name: Set up Go 1.17.x uses: actions/setup-go@v2 with: - go-version: 1.16.x + go-version: 1.17.x id: go - name: Check out code uses: actions/checkout@v2 diff --git a/.github/workflows/code-style.yaml b/.github/workflows/code-style.yaml index 9760c63..700286c 100644 --- a/.github/workflows/code-style.yaml +++ b/.github/workflows/code-style.yaml @@ -40,10 +40,10 @@ jobs: importpath: golang.org/x/tools/cmd/goimports steps: - - name: Set up Go 1.16.x + - name: Set up Go 1.17.x uses: actions/setup-go@v2 with: - go-version: 1.16.x + go-version: 1.17.x id: go - name: Check out code @@ -90,10 +90,10 @@ jobs: runs-on: ubuntu-latest steps: - - name: Set up Go 1.16.x + - name: Set up Go 1.17.x uses: actions/setup-go@v2 with: - go-version: 1.16.x + go-version: 1.17.x id: go - name: Check out code diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index 772900f..f983ae0 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -24,10 +24,10 @@ jobs: name: Run unit tests runs-on: ubuntu-latest steps: - - name: Set up Go 1.16.x + - name: Set up Go 1.17.x uses: actions/setup-go@v2 with: - go-version: 1.16.x + go-version: 1.17.x id: go - name: Check out code uses: actions/checkout@v2 @@ -39,10 +39,10 @@ jobs: name: Run integration tests runs-on: ubuntu-latest steps: - - name: Set up Go 1.16.x + - name: Set up Go 1.17.x uses: actions/setup-go@v2 with: - go-version: 1.16.x + go-version: 1.17.x id: go - name: Check out code uses: actions/checkout@v2 @@ -67,10 +67,10 @@ jobs: name: Verify istio manifests runs-on: ubuntu-latest steps: - - name: Set up Go 1.16.x + - name: Set up Go 1.17.x uses: actions/setup-go@v2 with: - go-version: 1.16.x + go-version: 1.17.x id: go - name: Check out code uses: actions/checkout@v2 @@ -82,10 +82,10 @@ jobs: name: Verify Gateway API manifests runs-on: ubuntu-latest steps: - - name: Set up Go 1.16.x + - name: Set up Go 1.17.x uses: actions/setup-go@v2 with: - go-version: 1.16.x + go-version: 1.17.x id: go - name: Check out code uses: actions/checkout@v2 @@ -97,10 +97,10 @@ jobs: name: Verify kuadrant manifests runs-on: ubuntu-latest steps: - - name: Set up Go 1.16.x + - name: Set up Go 1.17.x uses: actions/setup-go@v2 with: - go-version: 1.16.x + go-version: 1.17.x id: go - name: Check out code uses: actions/checkout@v2 diff --git a/.gitignore b/.gitignore index 421070b..ee8161b 100644 --- a/.gitignore +++ b/.gitignore @@ -22,5 +22,6 @@ vendor *.swp *.swo *~ +.vscode/* kuadrant-controller diff --git a/Dockerfile b/Dockerfile index 7793809..cd7d034 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.16 as builder +FROM golang:1.17 as builder WORKDIR /workspace # Copy the Go Modules manifests diff --git a/Makefile b/Makefile index 9b7857c..d2fa34f 100644 --- a/Makefile +++ b/Makefile @@ -215,11 +215,11 @@ undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/confi CONTROLLER_GEN = $(shell pwd)/bin/controller-gen controller-gen: ## Download controller-gen locally if necessary. - $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.7.0) + $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.8.0) KUSTOMIZE = $(shell pwd)/bin/kustomize kustomize: ## Download kustomize locally if necessary. - $(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v3@v3.8.7) + $(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v4@v4.5.2) ENVTEST = $(shell pwd)/bin/setup-envtest envtest: ## Download envtest-setup locally if necessary. @@ -234,7 +234,7 @@ TMP_DIR=$$(mktemp -d) ;\ cd $$TMP_DIR ;\ go mod init tmp ;\ echo "Downloading $(2)" ;\ -GOBIN=$(PROJECT_DIR)/bin go get $(2) ;\ +GOBIN=$(PROJECT_DIR)/bin go install $(2) ;\ rm -rf $$TMP_DIR ;\ } endef @@ -306,7 +306,7 @@ kind: ## Download kind locally if necessary. $(call go-get-tool,$(KIND),sigs.k8s.io/kind@v0.11.1) $(GOLANGCI-LINT): - 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.46.1 .PHONY: golangci-lint golangci-lint: $(GOLANGCI-LINT) ## Download golangci-lint locally if necessary. diff --git a/README.md b/README.md index c95a5fc..34883d1 100644 --- a/README.md +++ b/README.md @@ -167,12 +167,13 @@ spec: EOF ``` -To verify wasm envoyfilter has been created: +To verify wasm wasmplugin has been created: ``` -kubectl get envoyfilter -A -NAMESPACE NAME AGE -kuadrant-system kuadrant-kuadrant-gwapi-gateway-wasm-ratelimits 3m4s +kubectl get wasmplugin -A +NAMESPACE NAME AGE +kuadrant-system kuadrant-kuadrant-gwapi-gateway-wasm-postauth 16s +kuadrant-system kuadrant-kuadrant-gwapi-gateway-wasm-preauth 16s ``` To verify Limitador's RateLimit resources have been created: diff --git a/apis/apim/v1alpha1/authpolicy_types.go b/apis/apim/v1alpha1/authpolicy_types.go index 78d828b..0975fd0 100644 --- a/apis/apim/v1alpha1/authpolicy_types.go +++ b/apis/apim/v1alpha1/authpolicy_types.go @@ -6,10 +6,25 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - securityv1beta1 "istio.io/api/security/v1beta1" gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" ) +type OperationWrapper struct { + Hosts []string `json:"hosts,omitempty"` + NotHosts []string `json:"not_hosts,omitempty"` + Ports []string `json:"ports,omitempty"` + NotPorts []string `json:"not_ports,omitempty"` + Methods []string `json:"methods,omitempty"` + NotMethods []string `json:"not_methods,omitempty"` + Paths []string `json:"paths,omitempty"` + NotPaths []string `json:"not_paths,omitempty"` +} + +// TODO(rahul): remove the following wrappers once https://github.com/istio/api/issues/2352 is fixed. +type RuleWrapper struct { + Operations []*OperationWrapper `json:"from,omitempty"` +} + // +kubebuilder:validation:Enum=ALLOW;CUSTOM;DENY;AUDIT type AuthPolicyAction string @@ -18,7 +33,7 @@ type AuthPolicyConfig struct { Action AuthPolicyAction `json:"action"` // A list of rules to match the request. A match occurs when at least one rule matches the request. - Rules []securityv1beta1.Rule `json:"rules,omitempty"` + Rules []*RuleWrapper `json:"rules,omitempty"` // +kubebuilder:default="" // Specifies detailed configuration of the CUSTOM action. Must be used only with CUSTOM action. diff --git a/apis/apim/v1alpha1/zz_generated.deepcopy.go b/apis/apim/v1alpha1/zz_generated.deepcopy.go index 40b0b81..599cff2 100644 --- a/apis/apim/v1alpha1/zz_generated.deepcopy.go +++ b/apis/apim/v1alpha1/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* @@ -22,7 +23,6 @@ package v1alpha1 import ( apiv1alpha1 "github.com/kuadrant/limitador-operator/api/v1alpha1" - "istio.io/api/security/v1beta1" "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -93,9 +93,13 @@ func (in *AuthPolicyConfig) DeepCopyInto(out *AuthPolicyConfig) { *out = *in if in.Rules != nil { in, out := &in.Rules, &out.Rules - *out = make([]v1beta1.Rule, len(*in)) + *out = make([]*RuleWrapper, len(*in)) for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(RuleWrapper) + (*in).DeepCopyInto(*out) + } } } } @@ -275,6 +279,61 @@ func (in *Operation) DeepCopy() *Operation { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OperationWrapper) DeepCopyInto(out *OperationWrapper) { + *out = *in + if in.Hosts != nil { + in, out := &in.Hosts, &out.Hosts + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.NotHosts != nil { + in, out := &in.NotHosts, &out.NotHosts + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Ports != nil { + in, out := &in.Ports, &out.Ports + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.NotPorts != nil { + in, out := &in.NotPorts, &out.NotPorts + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Methods != nil { + in, out := &in.Methods, &out.Methods + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.NotMethods != nil { + in, out := &in.NotMethods, &out.NotMethods + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Paths != nil { + in, out := &in.Paths, &out.Paths + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.NotPaths != nil { + in, out := &in.NotPaths, &out.NotPaths + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperationWrapper. +func (in *OperationWrapper) DeepCopy() *OperationWrapper { + if in == nil { + return nil + } + out := new(OperationWrapper) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RateLimit) DeepCopyInto(out *RateLimit) { *out = *in @@ -498,3 +557,29 @@ func (in *Rule) DeepCopy() *Rule { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RuleWrapper) DeepCopyInto(out *RuleWrapper) { + *out = *in + if in.Operations != nil { + in, out := &in.Operations, &out.Operations + *out = make([]*OperationWrapper, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(OperationWrapper) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RuleWrapper. +func (in *RuleWrapper) DeepCopy() *RuleWrapper { + if in == nil { + return nil + } + out := new(RuleWrapper) + in.DeepCopyInto(out) + return out +} diff --git a/config/crd/bases/apim.kuadrant.io_authpolicies.yaml b/config/crd/bases/apim.kuadrant.io_authpolicies.yaml index 8f3361b..e70bbaa 100644 --- a/config/crd/bases/apim.kuadrant.io_authpolicies.yaml +++ b/config/crd/bases/apim.kuadrant.io_authpolicies.yaml @@ -1,10 +1,9 @@ - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.7.0 + controller-gen.kubebuilder.io/version: v0.8.0 creationTimestamp: null name: authpolicies.apim.kuadrant.io spec: @@ -57,204 +56,41 @@ spec: description: A list of rules to match the request. A match occurs when at least one rule matches the request. items: - description: "Rule matches requests from a list of sources - that perform a list of operations subject to a list of conditions. - A match occurs when at least one source, operation and condition - matches the request. An empty rule is always matched. \n - Any string field in the rule supports Exact, Prefix, Suffix - and Presence match: \n - Exact match: \"abc\" will match - on value \"abc\". - Prefix match: \"abc*\" will match on - value \"abc\" and \"abcd\". - Suffix match: \"*abc\" will - match on value \"abc\" and \"xabc\". - Presence match: \"*\" - will match when value is not empty." + description: 'TODO(rahul): remove the following wrappers once + https://github.com/istio/api/issues/2352 is fixed.' properties: from: - description: "Optional. from specifies the source of a - request. \n If not set, any source is allowed." items: - description: From includes a list or sources. properties: - source: - description: Source specifies the source of a request. - properties: - ip_blocks: - description: "Optional. A list of IP blocks, - which matches to the \"source.ip\" attribute. - Populated from the source address of the IP - packet. Single IP (e.g. \"1.2.3.4\") and CIDR - (e.g. \"1.2.3.0/24\") are supported. \n If - not set, any IP is allowed." - items: - type: string - type: array - namespaces: - description: "Optional. A list of namespaces, - which matches to the \"source.namespace\" - attribute. This field requires mTLS enabled. - \n If not set, any namespace is allowed." - items: - type: string - type: array - not_ip_blocks: - description: Optional. A list of negative match - of IP blocks. - items: - type: string - type: array - not_namespaces: - description: Optional. A list of negative match - of namespaces. - items: - type: string - type: array - not_principals: - description: Optional. A list of negative match - of source peer identities. - items: - type: string - type: array - not_remote_ip_blocks: - description: Optional. A list of negative match - of remote IP blocks. - items: - type: string - type: array - not_request_principals: - description: Optional. A list of negative match - of request identities. - items: - type: string - type: array - principals: - description: "Optional. A list of source peer - identities (i.e. service account), which matches - to the \"source.principal\" attribute. This - field requires mTLS enabled. \n If not set, - any principal is allowed." - items: - type: string - type: array - remote_ip_blocks: - description: "Optional. A list of IP blocks, - which matches to the \"remote.ip\" attribute. - Populated from X-Forwarded-For header or proxy - protocol. To make use of this field, you must - configure the numTrustedProxies field of the - gatewayTopology under the meshConfig when - you install Istio or using an annotation on - the ingress gateway. See the documentation - here: [Configuring Gateway Network Topology](https://istio.io/latest/docs/ops/configuration/traffic-management/network-topologies/). - Single IP (e.g. \"1.2.3.4\") and CIDR (e.g. - \"1.2.3.0/24\") are supported. \n If not set, - any IP is allowed." - items: - type: string - type: array - request_principals: - description: "Optional. A list of request identities - (i.e. \"iss/sub\" claims), which matches to - the \"request.auth.principal\" attribute. - \n If not set, any request principal is allowed." - items: - type: string - type: array - type: object - type: object - type: array - to: - description: "Optional. to specifies the operation of - a request. \n If not set, any operation is allowed." - items: - description: To includes a list or operations. - properties: - operation: - description: Operation specifies the operation of - a request. - properties: - hosts: - description: "Optional. A list of hosts, which - matches to the \"request.host\" attribute. - \n If not set, any host is allowed. Must be - used only with HTTP." - items: - type: string - type: array - methods: - description: "Optional. A list of methods, which - matches to the \"request.method\" attribute. - For gRPC service, this will always be \"POST\". - \n If not set, any method is allowed. Must - be used only with HTTP." - items: - type: string - type: array - not_hosts: - description: Optional. A list of negative match - of hosts. - items: - type: string - type: array - not_methods: - description: Optional. A list of negative match - of methods. - items: - type: string - type: array - not_paths: - description: Optional. A list of negative match - of paths. - items: - type: string - type: array - not_ports: - description: Optional. A list of negative match - of ports. - items: - type: string - type: array - paths: - description: "Optional. A list of paths, which - matches to the \"request.url_path\" attribute. - For gRPC service, this will be the fully-qualified - name in the form of \"/package.service/method\". - \n If not set, any path is allowed. Must be - used only with HTTP." - items: - type: string - type: array - ports: - description: "Optional. A list of ports, which - matches to the \"destination.port\" attribute. - \n If not set, any port is allowed." - items: - type: string - type: array - type: object - type: object - type: array - when: - description: "Optional. when specifies a list of additional - conditions of a request. \n If not set, any condition - is allowed." - items: - description: Condition specifies additional required - attributes. - properties: - key: - description: The name of an Istio attribute. See - the [full list of supported attributes](https://istio.io/docs/reference/config/security/conditions/). - type: string - not_values: - description: 'Optional. A list of negative match - of values for the attribute. Note: at least one - of values or not_values must be set.' + hosts: + items: + type: string + type: array + methods: + items: + type: string + type: array + not_hosts: + items: + type: string + type: array + not_methods: + items: + type: string + type: array + not_paths: + items: + type: string + type: array + not_ports: + items: + type: string + type: array + paths: items: type: string type: array - values: - description: 'Optional. A list of allowed values - for the attribute. Note: at least one of values - or not_values must be set.' + ports: items: type: string type: array diff --git a/config/crd/bases/apim.kuadrant.io_ratelimitpolicies.yaml b/config/crd/bases/apim.kuadrant.io_ratelimitpolicies.yaml index 1f9d014..08fce7d 100644 --- a/config/crd/bases/apim.kuadrant.io_ratelimitpolicies.yaml +++ b/config/crd/bases/apim.kuadrant.io_ratelimitpolicies.yaml @@ -1,10 +1,9 @@ - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.7.0 + controller-gen.kubebuilder.io/version: v0.8.0 creationTimestamp: null name: ratelimitpolicies.apim.kuadrant.io spec: @@ -303,13 +302,12 @@ spec: description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, - type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: - \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // +listMapKey=type - \ Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" + type FooStatus struct{ // Represents the observations of a foo's + current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" properties: lastTransitionTime: description: lastTransitionTime is the last time the condition diff --git a/config/deploy/manifests.yaml b/config/deploy/manifests.yaml index 4c4d7dc..a224c77 100644 --- a/config/deploy/manifests.yaml +++ b/config/deploy/manifests.yaml @@ -10,7 +10,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.7.0 + controller-gen.kubebuilder.io/version: v0.8.0 creationTimestamp: null labels: app: kuadrant @@ -29,21 +29,27 @@ spec: openAPIV3Schema: properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: type: object spec: properties: policy: - description: Policy per action type but also per provider if using custom type. + description: Policy per action type but also per provider if using + custom type. items: properties: action: - description: The action to take if the request is matches with the rules. + description: The action to take if the request is matches with + the rules. enum: - ALLOW - CUSTOM @@ -52,140 +58,48 @@ spec: type: string provider: default: "" - description: Specifies detailed configuration of the CUSTOM action. Must be used only with CUSTOM action. + description: Specifies detailed configuration of the CUSTOM + action. Must be used only with CUSTOM action. type: string rules: - description: A list of rules to match the request. A match occurs when at least one rule matches the request. + description: A list of rules to match the request. A match occurs + when at least one rule matches the request. items: - description: "Rule matches requests from a list of sources that perform a list of operations subject to a list of conditions. A match occurs when at least one source, operation and condition matches the request. An empty rule is always matched. \n Any string field in the rule supports Exact, Prefix, Suffix and Presence match: \n - Exact match: \"abc\" will match on value \"abc\". - Prefix match: \"abc*\" will match on value \"abc\" and \"abcd\". - Suffix match: \"*abc\" will match on value \"abc\" and \"xabc\". - Presence match: \"*\" will match when value is not empty." + description: 'TODO(rahul): remove the following wrappers once + https://github.com/istio/api/issues/2352 is fixed.' properties: from: - description: "Optional. from specifies the source of a request. \n If not set, any source is allowed." items: - description: From includes a list or sources. properties: - source: - description: Source specifies the source of a request. - properties: - ip_blocks: - description: "Optional. A list of IP blocks, which matches to the \"source.ip\" attribute. Populated from the source address of the IP packet. Single IP (e.g. \"1.2.3.4\") and CIDR (e.g. \"1.2.3.0/24\") are supported. \n If not set, any IP is allowed." - items: - type: string - type: array - namespaces: - description: "Optional. A list of namespaces, which matches to the \"source.namespace\" attribute. This field requires mTLS enabled. \n If not set, any namespace is allowed." - items: - type: string - type: array - not_ip_blocks: - description: Optional. A list of negative match of IP blocks. - items: - type: string - type: array - not_namespaces: - description: Optional. A list of negative match of namespaces. - items: - type: string - type: array - not_principals: - description: Optional. A list of negative match of source peer identities. - items: - type: string - type: array - not_remote_ip_blocks: - description: Optional. A list of negative match of remote IP blocks. - items: - type: string - type: array - not_request_principals: - description: Optional. A list of negative match of request identities. - items: - type: string - type: array - principals: - description: "Optional. A list of source peer identities (i.e. service account), which matches to the \"source.principal\" attribute. This field requires mTLS enabled. \n If not set, any principal is allowed." - items: - type: string - type: array - remote_ip_blocks: - description: "Optional. A list of IP blocks, which matches to the \"remote.ip\" attribute. Populated from X-Forwarded-For header or proxy protocol. To make use of this field, you must configure the numTrustedProxies field of the gatewayTopology under the meshConfig when you install Istio or using an annotation on the ingress gateway. See the documentation here: [Configuring Gateway Network Topology](https://istio.io/latest/docs/ops/configuration/traffic-management/network-topologies/). Single IP (e.g. \"1.2.3.4\") and CIDR (e.g. \"1.2.3.0/24\") are supported. \n If not set, any IP is allowed." - items: - type: string - type: array - request_principals: - description: "Optional. A list of request identities (i.e. \"iss/sub\" claims), which matches to the \"request.auth.principal\" attribute. \n If not set, any request principal is allowed." - items: - type: string - type: array - type: object - type: object - type: array - to: - description: "Optional. to specifies the operation of a request. \n If not set, any operation is allowed." - items: - description: To includes a list or operations. - properties: - operation: - description: Operation specifies the operation of a request. - properties: - hosts: - description: "Optional. A list of hosts, which matches to the \"request.host\" attribute. \n If not set, any host is allowed. Must be used only with HTTP." - items: - type: string - type: array - methods: - description: "Optional. A list of methods, which matches to the \"request.method\" attribute. For gRPC service, this will always be \"POST\". \n If not set, any method is allowed. Must be used only with HTTP." - items: - type: string - type: array - not_hosts: - description: Optional. A list of negative match of hosts. - items: - type: string - type: array - not_methods: - description: Optional. A list of negative match of methods. - items: - type: string - type: array - not_paths: - description: Optional. A list of negative match of paths. - items: - type: string - type: array - not_ports: - description: Optional. A list of negative match of ports. - items: - type: string - type: array - paths: - description: "Optional. A list of paths, which matches to the \"request.url_path\" attribute. For gRPC service, this will be the fully-qualified name in the form of \"/package.service/method\". \n If not set, any path is allowed. Must be used only with HTTP." - items: - type: string - type: array - ports: - description: "Optional. A list of ports, which matches to the \"destination.port\" attribute. \n If not set, any port is allowed." - items: - type: string - type: array - type: object - type: object - type: array - when: - description: "Optional. when specifies a list of additional conditions of a request. \n If not set, any condition is allowed." - items: - description: Condition specifies additional required attributes. - properties: - key: - description: The name of an Istio attribute. See the [full list of supported attributes](https://istio.io/docs/reference/config/security/conditions/). - type: string - not_values: - description: 'Optional. A list of negative match of values for the attribute. Note: at least one of values or not_values must be set.' + hosts: items: type: string type: array - values: - description: 'Optional. A list of allowed values for the attribute. Note: at least one of values or not_values must be set.' + methods: + items: + type: string + type: array + not_hosts: + items: + type: string + type: array + not_methods: + items: + type: string + type: array + not_paths: + items: + type: string + type: array + not_ports: + items: + type: string + type: array + paths: + items: + type: string + type: array + ports: items: type: string type: array @@ -221,7 +135,10 @@ spec: minLength: 1 type: string namespace: - description: Namespace is the namespace of the referent. When unspecified, the local namespace is inferred. Even when policy targets a resource in a different namespace, it MUST only apply to traffic originating from the same namespace as the policy. + description: Namespace is the namespace of the referent. When + unspecified, the local namespace is inferred. Even when policy + targets a resource in a different namespace, it MUST only apply + to traffic originating from the same namespace as the policy. maxLength: 63 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ @@ -248,7 +165,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.7.0 + controller-gen.kubebuilder.io/version: v0.8.0 creationTimestamp: null labels: app: kuadrant @@ -268,10 +185,14 @@ spec: description: RateLimitPolicy is the Schema for the ratelimitpolicies API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: type: object @@ -311,7 +232,8 @@ spec: properties: actions: items: - description: Action_Specifier defines one envoy rate limit action + description: Action_Specifier defines one envoy rate limit + action oneOf: - required: - generic_key @@ -365,10 +287,12 @@ spec: - metadata_key type: object remote_address: - description: RemoteAddressSpec no need to specify descriptor entry is populated using the trusted address from [x-forwarded-for](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#config-http-conn-man-headers-x-forwarded-for) + description: RemoteAddressSpec no need to specify descriptor + entry is populated using the trusted address from [x-forwarded-for](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#config-http-conn-man-headers-x-forwarded-for) type: object request_headers: - description: RequestHeadersSpec Rate limit on request headers. + description: RequestHeadersSpec Rate limit on request + headers. properties: descriptor_key: type: string @@ -383,7 +307,8 @@ spec: type: object type: array stage: - description: 'Definfing phase at which rate limits will be applied. Valid values are: PREAUTH, POSTAUTH, BOTH' + description: 'Definfing phase at which rate limits will be applied. + Valid values are: PREAUTH, POSTAUTH, BOTH' enum: - PREAUTH - POSTAUTH @@ -397,12 +322,16 @@ spec: items: properties: name: - description: Name supports regex for fetching operations from routing resources For VirtualService, if route name matches, all the match requests are converted to operations internally. But specific match request names are also supported. + description: Name supports regex for fetching operations from + routing resources For VirtualService, if route name matches, + all the match requests are converted to operations internally. + But specific match request names are also supported. type: string operations: description: Operation specifies the operations of a request items: - description: Each operation type has OR semantics and overall AND semantics for a match. + description: Each operation type has OR semantics and overall + AND semantics for a match. properties: methods: items: @@ -419,7 +348,8 @@ spec: properties: actions: items: - description: Action_Specifier defines one envoy rate limit action + description: Action_Specifier defines one envoy rate + limit action oneOf: - required: - generic_key @@ -473,10 +403,13 @@ spec: - metadata_key type: object remote_address: - description: RemoteAddressSpec no need to specify descriptor entry is populated using the trusted address from [x-forwarded-for](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#config-http-conn-man-headers-x-forwarded-for) + description: RemoteAddressSpec no need to specify + descriptor entry is populated using the trusted + address from [x-forwarded-for](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#config-http-conn-man-headers-x-forwarded-for) type: object request_headers: - description: RequestHeadersSpec Rate limit on request headers. + description: RequestHeadersSpec Rate limit on request + headers. properties: descriptor_key: type: string @@ -491,7 +424,8 @@ spec: type: object type: array stage: - description: 'Definfing phase at which rate limits will be applied. Valid values are: PREAUTH, POSTAUTH, BOTH' + description: 'Definfing phase at which rate limits will + be applied. Valid values are: PREAUTH, POSTAUTH, BOTH' enum: - PREAUTH - POSTAUTH @@ -523,7 +457,10 @@ spec: minLength: 1 type: string namespace: - description: Namespace is the namespace of the referent. When unspecified, the local namespace is inferred. Even when policy targets a resource in a different namespace, it MUST only apply to traffic originating from the same namespace as the policy. + description: Namespace is the namespace of the referent. When + unspecified, the local namespace is inferred. Even when policy + targets a resource in a different namespace, it MUST only apply + to traffic originating from the same namespace as the policy. maxLength: 63 minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ @@ -541,25 +478,47 @@ spec: description: RateLimitPolicyStatus defines the observed state of RateLimitPolicy properties: conditions: - description: 'Represents the observations of a foo''s current state. Known .status.conditions.type are: "Available"' + description: 'Represents the observations of a foo''s current state. + Known .status.conditions.type are: "Available"' items: - description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + type FooStatus struct{ // Represents the observations of a foo's + current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be when + the underlying condition changed. If that is not known, then + using the time when the API field changed is acceptable. format: date-time type: string message: - description: message is a human readable message indicating details about the transition. This may be an empty string. + description: message is a human readable message indicating + details about the transition. This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if .metadata.generation + is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the current + state of the instance. format: int64 minimum: 0 type: integer reason: - description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values and + meanings for this field, and whether the values are considered + a guaranteed API. The value should be a CamelCase string. + This field may not be empty. maxLength: 1024 minLength: 1 pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ @@ -572,7 +531,11 @@ spec: - Unknown type: string type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string @@ -588,7 +551,8 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: ObservedGeneration reflects the generation of the most recently observed spec. + description: ObservedGeneration reflects the generation of the most + recently observed spec. format: int64 type: integer type: object @@ -695,39 +659,39 @@ rules: - patch - update - apiGroups: - - gateway.networking.k8s.io + - extensions.istio.io resources: - - gateways + - wasmplugins verbs: + - create + - delete - get - list + - patch + - update - watch - apiGroups: - gateway.networking.k8s.io resources: - - httproutes + - gateways verbs: - get - list - - patch - - update - watch - apiGroups: - - limitador.kuadrant.io + - gateway.networking.k8s.io resources: - - ratelimits + - httproutes verbs: - - create - - delete - get - list - patch - update - watch - apiGroups: - - networking.istio.io + - limitador.kuadrant.io resources: - - envoyfilters + - ratelimits verbs: - create - delete diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index bb9be33..fce41d9 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -1,4 +1,3 @@ - --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -51,39 +50,39 @@ rules: - patch - update - apiGroups: - - gateway.networking.k8s.io + - extensions.istio.io resources: - - gateways + - wasmplugins verbs: + - create + - delete - get - list + - patch + - update - watch - apiGroups: - gateway.networking.k8s.io resources: - - httproutes + - gateways verbs: - get - list - - patch - - update - watch - apiGroups: - - limitador.kuadrant.io + - gateway.networking.k8s.io resources: - - ratelimits + - httproutes verbs: - - create - - delete - get - list - patch - update - watch - apiGroups: - - networking.istio.io + - limitador.kuadrant.io resources: - - envoyfilters + - ratelimits verbs: - create - delete diff --git a/controllers/apim/authpolicy_controller.go b/controllers/apim/authpolicy_controller.go index 27b8126..0e7dd2a 100644 --- a/controllers/apim/authpolicy_controller.go +++ b/controllers/apim/authpolicy_controller.go @@ -86,7 +86,7 @@ func (r *AuthPolicyReconciler) Reconcile(eventCtx context.Context, req ctrl.Requ // IstioAuthPolicy generates Istio's AuthorizationPolicy using Kuadrant's AuthPolicy func (r *AuthPolicyReconciler) reconcileAuthPolicy(ctx context.Context, ap *apimv1alpha1.AuthPolicy) error { - logger := logr.FromContext(ctx) + logger, _ := logr.FromContext(ctx) if err := ap.Validate(); err != nil { return err @@ -120,13 +120,30 @@ func (r *AuthPolicyReconciler) reconcileAuthPolicy(ctx context.Context, ap *apim // convert []Rule to []*Rule rulePtrSlice := []*secv1beta1types.Rule{} for idx := range policyConfig.Rules { + rule := &secv1beta1types.Rule{ + To: []*secv1beta1types.Rule_To{}, + } // TODO(rahulanand16nov): Do the check and append instead of force hostname from httproute - for _, toRule := range policyConfig.Rules[idx].To { - if toRule.Operation != nil { - toRule.Operation.Hosts = HostnamesToStrings(httpRoute.Spec.Hostnames) + for _, operation := range policyConfig.Rules[idx].Operations { + if operation != nil { + operation.Hosts = HostnamesToStrings(httpRoute.Spec.Hostnames) + } + // TODO(rahul): we'll revert back to using the structs directly once + // https://github.com/kubernetes-sigs/controller-tools/pull/584 is present in a release. + toRule := &secv1beta1types.Rule_To{ + Operation: &secv1beta1types.Operation{ + NotHosts: operation.NotHosts, + Ports: operation.Ports, + NotPorts: operation.NotPorts, + Methods: operation.Methods, + NotMethods: operation.NotMethods, + Paths: operation.Paths, + NotPaths: operation.NotPaths, + }, } + rule.To = append(rule.To, toRule) } - rulePtrSlice = append(rulePtrSlice, &policyConfig.Rules[idx]) + rulePtrSlice = append(rulePtrSlice, rule) } actionInt := secv1beta1types.AuthorizationPolicy_Action_value[string(policyConfig.Action)] @@ -166,7 +183,7 @@ func (r *AuthPolicyReconciler) reconcileAuthPolicy(ctx context.Context, ap *apim } func (r *AuthPolicyReconciler) reconcileNetworkResourceBackReference(ctx context.Context, ap *apimv1alpha1.AuthPolicy) error { - logger := logr.FromContext(ctx) + logger, _ := logr.FromContext(ctx) httpRoute, err := r.fetchHTTPRoute(ctx, ap) if err != nil { // The object should also exist @@ -199,7 +216,7 @@ func (r *AuthPolicyReconciler) reconcileNetworkResourceBackReference(ctx context } func (r *AuthPolicyReconciler) removeIstioAuthPolicy(ctx context.Context, ap *apimv1alpha1.AuthPolicy) error { - logger := logr.FromContext(ctx) + logger, _ := logr.FromContext(ctx) logger.Info("Removing Istio's AuthorizationPolicy") httpRoute, err := r.fetchHTTPRoute(ctx, ap) @@ -243,7 +260,7 @@ func (r *AuthPolicyReconciler) removeIstioAuthPolicy(ctx context.Context, ap *ap // fetchHTTPRoute fetches the HTTPRoute described in targetRef *within* AuthPolicy's namespace. func (r *AuthPolicyReconciler) fetchHTTPRoute(ctx context.Context, ap *apimv1alpha1.AuthPolicy) (*gatewayapiv1alpha2.HTTPRoute, error) { - logger := logr.FromContext(ctx) + logger, _ := logr.FromContext(ctx) key := client.ObjectKey{ Name: string(ap.Spec.TargetRef.Name), Namespace: ap.Namespace, diff --git a/controllers/apim/httproute_controller.go b/controllers/apim/httproute_controller.go index e4b1a3b..60b0894 100644 --- a/controllers/apim/httproute_controller.go +++ b/controllers/apim/httproute_controller.go @@ -142,16 +142,6 @@ func (r *HTTPRouteReconciler) reconcileAuthPolicy(ctx context.Context, logger lo rules = append(rules, rule) } - authPolicySpec := securityv1beta1.AuthorizationPolicy{ - Rules: rules, - Action: securityv1beta1.AuthorizationPolicy_CUSTOM, - ActionDetail: &securityv1beta1.AuthorizationPolicy_Provider{ - Provider: &securityv1beta1.AuthorizationPolicy_ExtensionProvider{ - Name: providerName, - }, - }, - } - for _, parentRef := range hr.Spec.ParentRefs { gwNamespace := hr.Namespace // consider gateway local if namespace is not given if parentRef.Namespace != nil { @@ -164,7 +154,15 @@ func (r *HTTPRouteReconciler) reconcileAuthPolicy(ctx context.Context, logger lo Name: getAuthPolicyName(gwName, hr.Name, "custom"), Namespace: gwNamespace, }, - Spec: authPolicySpec, + Spec: securityv1beta1.AuthorizationPolicy{ + Rules: rules, + Action: securityv1beta1.AuthorizationPolicy_CUSTOM, + ActionDetail: &securityv1beta1.AuthorizationPolicy_Provider{ + Provider: &securityv1beta1.AuthorizationPolicy_ExtensionProvider{ + Name: providerName, + }, + }, + }, } err := r.ReconcileResource(ctx, &istiosecurityv1beta1.AuthorizationPolicy{}, &authPolicy, alwaysUpdateAuthPolicy) diff --git a/controllers/apim/ratelimitpolicy_controller.go b/controllers/apim/ratelimitpolicy_controller.go index 9c6f4fd..68913ad 100644 --- a/controllers/apim/ratelimitpolicy_controller.go +++ b/controllers/apim/ratelimitpolicy_controller.go @@ -24,7 +24,7 @@ import ( "github.com/go-logr/logr" "github.com/kuadrant/limitador-operator/api/v1alpha1" - istionetworkingv1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3" + istioextensionv1alpha3 "istio.io/client-go/pkg/apis/extensions/v1alpha1" apierrors "k8s.io/apimachinery/pkg/api/errors" meta "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" @@ -51,7 +51,7 @@ type RateLimitPolicyReconciler struct { //+kubebuilder:rbac:groups=apim.kuadrant.io,resources=ratelimitpolicies/status,verbs=get;update;patch //+kubebuilder:rbac:groups=apim.kuadrant.io,resources=ratelimitpolicies/finalizers,verbs=update //+kubebuilder:rbac:groups=networking.istio.io,resources=gateways,verbs=get;list;watch -//+kubebuilder:rbac:groups=networking.istio.io,resources=envoyfilters,verbs=get;list;watch;create;delete;update;patch +//+kubebuilder:rbac:groups=extensions.istio.io,resources=wasmplugins,verbs=get;list;watch;create;delete;update;patch //+kubebuilder:rbac:groups=limitador.kuadrant.io,resources=ratelimits,verbs=get;list;watch;create;update;delete;patch // Reconcile is part of the main kubernetes reconciliation loop which aims to @@ -80,7 +80,7 @@ func (r *RateLimitPolicyReconciler) Reconcile(eventCtx context.Context, req ctrl if rlp.GetDeletionTimestamp() != nil && controllerutil.ContainsFinalizer(rlp, rateLimitPolicyFinalizer) { logger.V(1).Info("Handling removal of ratelimitpolicy object") - if err := r.finalizeWASMEnvoyFilters(ctx, rlp); err != nil { + if err := r.finalizeWASMPlugins(ctx, rlp); err != nil { return ctrl.Result{}, err } if err := r.deleteRateLimits(ctx, rlp); err != nil { @@ -157,11 +157,11 @@ func (r *RateLimitPolicyReconciler) reconcileSpec(ctx context.Context, rlp *apim return ctrl.Result{}, err } - if err := r.reconcileWASMEnvoyFilters(ctx, rlp); err != nil { + if err := r.reconcileWASMPlugins(ctx, rlp); err != nil { return ctrl.Result{}, err } - if err := r.cleanUpOrphanWASMEnvoyFilters(ctx, rlp); err != nil { + if err := r.cleanUpOrphanWASMPlugins(ctx, rlp); err != nil { return ctrl.Result{}, err } @@ -169,7 +169,7 @@ func (r *RateLimitPolicyReconciler) reconcileSpec(ctx context.Context, rlp *apim } func (r *RateLimitPolicyReconciler) reconcileLimits(ctx context.Context, rlp *apimv1alpha1.RateLimitPolicy) error { - logger := logr.FromContext(ctx) + logger, _ := logr.FromContext(ctx) rlpKey := client.ObjectKeyFromObject(rlp) // create the RateLimit resource @@ -200,7 +200,7 @@ func (r *RateLimitPolicyReconciler) reconcileLimits(ctx context.Context, rlp *ap } func (r *RateLimitPolicyReconciler) reconcileNetworkResourceBackReference(ctx context.Context, rlp *apimv1alpha1.RateLimitPolicy) error { - logger := logr.FromContext(ctx) + logger, _ := logr.FromContext(ctx) httpRoute, err := r.fetchHTTPRoute(ctx, rlp) if err != nil { // The object should also exist @@ -232,19 +232,20 @@ func (r *RateLimitPolicyReconciler) reconcileNetworkResourceBackReference(ctx co return nil } -// Finds gateways with envoyFilters with rate limit configuration from the current RLP +// Finds gateways with WASMPLugins with rate limit configuration from the current RLP // Delete RL conf from the current RLP from gateways not referenced by the current RLP // Cleans up RL conf when: // - HTTPRoute updates parentRefs (gateways) // - RLP updates targetRef to another HTTPRoute -func (r *RateLimitPolicyReconciler) cleanUpOrphanWASMEnvoyFilters(ctx context.Context, rlp *apimv1alpha1.RateLimitPolicy) error { - logger := logr.FromContext(ctx) +func (r *RateLimitPolicyReconciler) cleanUpOrphanWASMPlugins(ctx context.Context, rlp *apimv1alpha1.RateLimitPolicy) error { + logger, _ := logr.FromContext(ctx) currentGatewayRefs, err := r.gatewayRefList(ctx, rlp) if err != nil { return err } + // TODO(rahulanand16nov): maybe think about optimizing it with a label later gwList := &gatewayapiv1alpha2.GatewayList{} err = r.Client().List(ctx, gwList) if err != nil { @@ -258,30 +259,33 @@ func (r *RateLimitPolicyReconciler) cleanUpOrphanWASMEnvoyFilters(ctx context.Co notReferencedGatewayKeys := common.ObjectKeyListDifference(gwKeyList, currentGatewayRefs) + RateLimitStages := []apimv1alpha1.RateLimitStage{apimv1alpha1.RateLimitStagePREAUTH, apimv1alpha1.RateLimitStagePOSTAUTH} for _, gwKey := range notReferencedGatewayKeys { - wasmKey := kuadrantistioutils.WASMEnvoyFilterKey(gwKey) - - envoyFilter := &istionetworkingv1alpha3.EnvoyFilter{} - err = r.Client().Get(ctx, wasmKey, envoyFilter) - logger.V(1).Info("cleanUpOrphanWASMEnvoyFilters: get EnvoyFilter", "envoyFilter", wasmKey, "err", err) - if apierrors.IsNotFound(err) { - logger.V(1).Info("cleanUpOrphanWASMEnvoyFilters: envoyfilter not found. Nothing to do", "envoyfilter", wasmKey) - continue - } - if err != nil { - return err - } - err = r.finalizeSingleWASMEnvoyFilter(ctx, rlp, envoyFilter) - if err != nil { - return err + for _, stage := range RateLimitStages { + wasmKey := kuadrantistioutils.WASMPluginKey(gwKey, stage) + + wasmplugin := &istioextensionv1alpha3.WasmPlugin{} + err = r.Client().Get(ctx, wasmKey, wasmplugin) + logger.V(1).Info("cleanUpOrphanWASMPlugins: get WasmPlugin", "wasmplugin", wasmKey, "err", err) + if apierrors.IsNotFound(err) { + logger.V(1).Info("cleanUpOrphanWASMPlugins: wasmplugin not found. Nothing to do", "wasmplugin", wasmKey) + continue + } + if err != nil { + return err + } + err = r.finalizeSingleWASMPlugins(ctx, rlp, wasmplugin) + if err != nil { + return err + } } } return nil } -func (r *RateLimitPolicyReconciler) reconcileWASMEnvoyFilters(ctx context.Context, rlp *apimv1alpha1.RateLimitPolicy) error { - logger := logr.FromContext(ctx) +func (r *RateLimitPolicyReconciler) reconcileWASMPlugins(ctx context.Context, rlp *apimv1alpha1.RateLimitPolicy) error { + logger, _ := logr.FromContext(ctx) httpRoute, err := r.fetchHTTPRoute(ctx, rlp) if err != nil { @@ -298,31 +302,33 @@ func (r *RateLimitPolicyReconciler) reconcileWASMEnvoyFilters(ctx context.Contex gwKey := currentGatewayRefs[idx] gateway := &gatewayapiv1alpha2.Gateway{} err := r.Client().Get(ctx, gwKey, gateway) - logger.V(1).Info("reconcileWASMEnvoyFilters: get Gateway", "gateway", gwKey, "err", err) + logger.V(1).Info("reconcileWASMPlugins: get Gateway", "gateway", gwKey, "err", err) if err != nil { // gateway needs to exist return err } - // Reconcile one EnvoyFilter per gateway + // Reconcile two WasmPlugins per gateway // Gateway API Gateway resource labels will be copied to the deployment in the automated deployment - // For the manual deployment, the Gateway resource labels must match deployment/pod labels or envoyfilters selector will not match + // For the manual deployment, the Gateway resource labels must match deployment/pod labels or WASMPlugins selector will not match // https://istio.io/latest/docs/tasks/traffic-management/ingress/gateway-api/#automated-deployment - ef, err := kuadrantistioutils.WASMEnvoyFilter(rlp, gwKey, gateway.GetLabels(), httpRoute.Spec.Hostnames) + wps, err := kuadrantistioutils.WasmPlugins(rlp, gwKey, gateway.GetLabels(), httpRoute.Spec.Hostnames) if err != nil { return err } - err = r.ReconcileResource(ctx, &istionetworkingv1alpha3.EnvoyFilter{}, ef, kuadrantistioutils.WASMEnvoyFilterPluginMutator) - if err != nil { - return err + for _, wp := range wps { + err = r.ReconcileResource(ctx, &istioextensionv1alpha3.WasmPlugin{}, wp, kuadrantistioutils.WASMPluginMutator) + if err != nil { + return err + } } } return nil } func (r *RateLimitPolicyReconciler) fetchHTTPRoute(ctx context.Context, rlp *apimv1alpha1.RateLimitPolicy) (*gatewayapiv1alpha2.HTTPRoute, error) { - logger := logr.FromContext(ctx) + logger, _ := logr.FromContext(ctx) tmpNS := rlp.Namespace if rlp.Spec.TargetRef.Namespace != nil { diff --git a/controllers/apim/ratelimitpolicy_finalizers.go b/controllers/apim/ratelimitpolicy_finalizers.go index 22a23d5..a402aed 100644 --- a/controllers/apim/ratelimitpolicy_finalizers.go +++ b/controllers/apim/ratelimitpolicy_finalizers.go @@ -3,11 +3,9 @@ package apim import ( "context" "encoding/json" - "fmt" "github.com/go-logr/logr" - protobuftypes "github.com/gogo/protobuf/types" - istionetworkingv1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3" + istioextensionv1alpha3 "istio.io/client-go/pkg/apis/extensions/v1alpha1" apierrors "k8s.io/apimachinery/pkg/api/errors" "sigs.k8s.io/controller-runtime/pkg/client" gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" @@ -22,9 +20,9 @@ const ( rateLimitPolicyFinalizer = "ratelimitpolicy.kuadrant.io/finalizer" ) -// finalizeWASMEnvoyFilters removes the configuration of this RLP from each gateway's EnvoyFilter. -func (r *RateLimitPolicyReconciler) finalizeWASMEnvoyFilters(ctx context.Context, rlp *apimv1alpha1.RateLimitPolicy) error { - logger := logr.FromContext(ctx) +// finalizeWASMPlugins removes the configuration of this RLP from each gateway's WASMPlugins. +func (r *RateLimitPolicyReconciler) finalizeWASMPlugins(ctx context.Context, rlp *apimv1alpha1.RateLimitPolicy) error { + logger, _ := logr.FromContext(ctx) httpRoute, err := r.fetchHTTPRoute(ctx, rlp) if err != nil { @@ -42,7 +40,7 @@ func (r *RateLimitPolicyReconciler) finalizeWASMEnvoyFilters(ctx context.Context } gateway := &gatewayapiv1alpha2.Gateway{} err := r.Client().Get(ctx, gwKey, gateway) - logger.V(1).Info("finalizeWASMEnvoyFilters: get Gateway", "gateway", gwKey, "err", err) + logger.V(1).Info("finalizeWASMPlugins: get Gateway", "gateway", gwKey, "err", err) if apierrors.IsNotFound(err) { logger.Info("parentRef Gateway not found", "parentRef", gwKey) continue @@ -51,84 +49,73 @@ func (r *RateLimitPolicyReconciler) finalizeWASMEnvoyFilters(ctx context.Context return err } - desiredEF, err := kuadrantistioutils.WASMEnvoyFilter(rlp, gwKey, gateway.GetLabels(), httpRoute.Spec.Hostnames) + desiredWPs, err := kuadrantistioutils.WasmPlugins(rlp, gwKey, gateway.GetLabels(), httpRoute.Spec.Hostnames) if err != nil { return err } - envoyFilter := &istionetworkingv1alpha3.EnvoyFilter{} - err = r.Client().Get(ctx, client.ObjectKeyFromObject(desiredEF), envoyFilter) - logger.V(1).Info("finalizeWASMEnvoyFilters: get EnvoyFilter", "envoyFilter", client.ObjectKeyFromObject(desiredEF), "err", err) - if apierrors.IsNotFound(err) { - logger.Info("finalizeWASMEnvoyFilters: envoyfilter not found", "envoyfilter", client.ObjectKeyFromObject(desiredEF)) - continue - } - if err != nil { - return err - } - err = r.finalizeSingleWASMEnvoyFilter(ctx, rlp, envoyFilter) - if err != nil { - return err + for _, desiredWP := range desiredWPs { + wasmPlugin := &istioextensionv1alpha3.WasmPlugin{} + err = r.Client().Get(ctx, client.ObjectKeyFromObject(desiredWP), wasmPlugin) + logger.V(1).Info("finalizeWASMPlugins: get WasmPlugin", "wasmplugin", client.ObjectKeyFromObject(desiredWP), "err", err) + if apierrors.IsNotFound(err) { + logger.Info("finalizeWASMPlugins: wasmplugin not found", "wasmplguin", client.ObjectKeyFromObject(desiredWP)) + continue + } + if err != nil { + return err + } + err = r.finalizeSingleWASMPlugins(ctx, rlp, wasmPlugin) + if err != nil { + return err + } } } return nil } -// finalizeSingleWASMEnvoyFilter removes the configuration of this RLP -// If the envoyfilter ends up with empty conf, the resource will be removed. -func (r *RateLimitPolicyReconciler) finalizeSingleWASMEnvoyFilter( - ctx context.Context, rlp *apimv1alpha1.RateLimitPolicy, envoyFilter *istionetworkingv1alpha3.EnvoyFilter, +// finalizeSingleWASMPlugins removes the configuration of this RLP +// If the WASMPlugin ends up with empty conf, the resource will be removed. +func (r *RateLimitPolicyReconciler) finalizeSingleWASMPlugins( + ctx context.Context, rlp *apimv1alpha1.RateLimitPolicy, wasmPlugin *istioextensionv1alpha3.WasmPlugin, ) error { - // first patch is PRE - // second patch is POST - configEmpty := []bool{false, false} updateObject := false - for idx := 0; idx < 2; idx++ { - patch := envoyFilter.Spec.ConfigPatches[idx] - pluginConfigFields := patch.Patch.Value.Fields["typed_config"]. - GetStructValue().Fields["value"].GetStructValue().Fields["config"].GetStructValue(). - Fields["configuration"].GetStructValue().Fields - pluginConfigStr := pluginConfigFields["value"].GetStringValue() - pluginConfig := &kuadrantistioutils.PluginConfig{} - if err := json.Unmarshal([]byte(pluginConfigStr), pluginConfig); err != nil { - return fmt.Errorf("finalizeSingleWASMEnvoyFilter: failed to unmarshal plugin config: %w", err) - } + configEmpty := false + // Deserialize config into PluginConfig struct + configJSON, err := wasmPlugin.Spec.PluginConfig.MarshalJSON() + if err != nil { + return err + } + pluginConfig := &kuadrantistioutils.PluginConfig{} + if err := json.Unmarshal(configJSON, pluginConfig); err != nil { + return err + } - pluginKey := client.ObjectKeyFromObject(rlp).String() - if _, ok := pluginConfig.PluginPolicies[pluginKey]; ok { - delete(pluginConfig.PluginPolicies, pluginKey) - updateObject = true - newPluginConfigSerialized, err := json.Marshal(pluginConfig) - if err != nil { - return fmt.Errorf("finalizeSingleWASMEnvoyFilter: failed to marshall new plugin config into json: %w", err) - } - // Update existing envoyfilter patch value - pluginConfigFields["value"] = &protobuftypes.Value{ - Kind: &protobuftypes.Value_StringValue{ - StringValue: string(newPluginConfigSerialized), - }, - } + pluginKey := client.ObjectKeyFromObject(rlp).String() + if _, ok := pluginConfig.PluginPolicies[pluginKey]; ok { + delete(pluginConfig.PluginPolicies, pluginKey) + updateObject = true + finalPluginConfig, err := kuadrantistioutils.PluginConfigToWasmPluginStruct(pluginConfig) + if err != nil { + return err } - configEmpty[idx] = len(pluginConfig.PluginPolicies) == 0 - } + wasmPlugin.Spec.PluginConfig = finalPluginConfig - allConfigEmpty := true - for idx := range configEmpty { - allConfigEmpty = allConfigEmpty && configEmpty[idx] + configEmpty = len(pluginConfig.PluginPolicies) == 0 } - if allConfigEmpty { - return r.DeleteResource(ctx, envoyFilter) + if configEmpty { + return r.DeleteResource(ctx, wasmPlugin) } else if updateObject { - return r.UpdateResource(ctx, envoyFilter) + return r.UpdateResource(ctx, wasmPlugin) } return nil } func (r *RateLimitPolicyReconciler) deleteRateLimits(ctx context.Context, rlp *apimv1alpha1.RateLimitPolicy) error { - logger := logr.FromContext(ctx) + logger, _ := logr.FromContext(ctx) rlpKey := client.ObjectKeyFromObject(rlp) for i := range rlp.Spec.Limits { ratelimitfactory := common.RateLimitFactory{ @@ -153,7 +140,7 @@ func (r *RateLimitPolicyReconciler) deleteRateLimits(ctx context.Context, rlp *a } func (r *RateLimitPolicyReconciler) deleteNetworkResourceBackReference(ctx context.Context, rlp *apimv1alpha1.RateLimitPolicy) error { - logger := logr.FromContext(ctx) + logger, _ := logr.FromContext(ctx) httpRoute, err := r.fetchHTTPRoute(ctx, rlp) if err != nil { if apierrors.IsNotFound(err) { diff --git a/controllers/apim/ratelimitpolicy_status.go b/controllers/apim/ratelimitpolicy_status.go index 38677c9..f4da6f0 100644 --- a/controllers/apim/ratelimitpolicy_status.go +++ b/controllers/apim/ratelimitpolicy_status.go @@ -20,7 +20,7 @@ const ( ) func (r *RateLimitPolicyReconciler) reconcileStatus(ctx context.Context, rlp *apimv1alpha1.RateLimitPolicy, specErr error) (ctrl.Result, error) { - logger := logr.FromContext(ctx) + logger, _ := logr.FromContext(ctx) newStatus := r.calculateStatus(rlp, specErr) equalStatus := rlp.Status.Equals(newStatus, logger) diff --git a/controllers/apim/utils.go b/controllers/apim/utils.go index 8f94256..c420f99 100644 --- a/controllers/apim/utils.go +++ b/controllers/apim/utils.go @@ -33,7 +33,10 @@ func alwaysUpdateAuthPolicy(existingObj, desiredObj client.Object) (bool, error) return false, fmt.Errorf("%T is not a *istiosecurityv1beta1.AuthorizationPolicy", desiredObj) } - existing.Spec = desired.Spec + existing.Spec.Action = desired.Spec.Action + existing.Spec.ActionDetail = desired.Spec.ActionDetail + existing.Spec.Rules = desired.Spec.Rules + existing.Spec.Selector = desired.Spec.Selector existing.Annotations = desired.Annotations return true, nil } diff --git a/go.mod b/go.mod index 29874c8..d2d6636 100644 --- a/go.mod +++ b/go.mod @@ -4,20 +4,20 @@ go 1.16 require ( github.com/Azure/go-autorest/autorest v0.11.19 // indirect - github.com/go-logr/logr v0.4.0 - github.com/gogo/protobuf v1.3.2 + github.com/go-logr/logr v1.2.0 + github.com/golang/protobuf v1.5.2 github.com/google/go-cmp v0.5.6 github.com/kuadrant/limitador-operator v0.2.0 - github.com/onsi/ginkgo v1.16.4 - github.com/onsi/gomega v1.15.0 - go.uber.org/zap v1.19.0 + github.com/onsi/ginkgo v1.16.5 + github.com/onsi/gomega v1.17.0 + go.uber.org/zap v1.19.1 gotest.tools v2.2.0+incompatible - istio.io/api v0.0.0-20210219142745-68975986cccb - istio.io/client-go v1.9.0 - k8s.io/api v0.22.1 - k8s.io/apimachinery v0.22.1 - k8s.io/client-go v0.22.1 - k8s.io/klog/v2 v2.10.0 - sigs.k8s.io/controller-runtime v0.10.0 + istio.io/api v0.0.0-20220516175159-89828b1f4baa + istio.io/client-go v1.13.3 + k8s.io/api v0.23.1 + k8s.io/apimachinery v0.23.1 + k8s.io/client-go v0.23.1 + k8s.io/klog/v2 v2.60.1 + sigs.k8s.io/controller-runtime v0.11.0 sigs.k8s.io/gateway-api v0.4.1 ) diff --git a/go.sum b/go.sum index 9bf4f45..b64cf4f 100644 --- a/go.sum +++ b/go.sum @@ -90,6 +90,7 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -122,6 +123,11 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= @@ -161,13 +167,15 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= -github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -175,8 +183,10 @@ github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -194,11 +204,13 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/zapr v0.2.0/go.mod h1:qhKdvif7YF5GI9NWEpyxTSSBdGmzkNguibrdCNVPunU= -github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM= github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= +github.com/go-logr/zapr v1.2.0 h1:n4JnPI1T3Qq1SFEi/F8rwLrZERp2bso19PJZDB9dayk= +github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= @@ -252,11 +264,11 @@ github.com/gobuffalo/flect v0.2.3/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20j github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -272,7 +284,6 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -294,6 +305,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= +github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -331,14 +344,12 @@ github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -386,10 +397,10 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -450,8 +461,9 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ 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 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +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/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -470,16 +482,17 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +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/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 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.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= -github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= -github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= @@ -510,8 +523,9 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.28.0 h1:vGVfV9KrDTvWt5boZO0I19g2E3CsWfpPPKZM9dt3mEw= +github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -585,6 +599,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/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= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= @@ -625,8 +640,10 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= @@ -637,11 +654,11 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -651,11 +668,11 @@ golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -679,7 +696,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -693,7 +709,6 @@ golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hM golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -717,7 +732,6 @@ golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -744,8 +758,12 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -757,8 +775,10 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 h1:0Ja1LBD+yisY6RWM/BH7TJVXWsSjs2VwBSmvSX4HdBc= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -770,7 +790,6 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -778,7 +797,6 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -794,7 +812,6 @@ golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -822,7 +839,6 @@ golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -839,15 +855,18 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 h1:c8PlLMqBbOHoqtjteWm5/kbe6rNY2pbRfbIMVnepueo= -golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8 h1:M69LAlWZCshgp0QSzyDcSsSIejIEeuaCVpmwcKwyLMk= +golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -855,8 +874,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -929,8 +949,8 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= 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= @@ -1002,6 +1022,7 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -1013,6 +1034,8 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 h1:NHN4wOCScVzKhPenJ2dt+BTs3X/XkBVI/Rh4iDt55T8= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1023,7 +1046,6 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= @@ -1036,6 +1058,8 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1047,8 +1071,9 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1092,97 +1117,97 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -istio.io/api v0.0.0-20210204223132-d90b2f705958/go.mod h1:88HN3o1fSD1jo+Z1WTLlJfMm9biopur6Ct9BFKjiB64= -istio.io/api v0.0.0-20210219142745-68975986cccb h1:0zYy68To6fDO/OricHJaQ8kzz0JvEmWMdeUdO3iN+vY= -istio.io/api v0.0.0-20210219142745-68975986cccb/go.mod h1:nsSFw1LIMmGL7r/+6fJI6FxeG/UGlLxRK8bkojIvBVs= -istio.io/client-go v1.9.0 h1:QSu9EgxXu9+fgtVc48GpriiGIP6c7CzO6J7ezeJMx2c= -istio.io/client-go v1.9.0/go.mod h1:KoaMRcxNR9zF7V54MSd/oj/dn+woe3zw07kdHFikDMk= -istio.io/gogo-genproto v0.0.0-20190930162913-45029607206a/go.mod h1:OzpAts7jljZceG4Vqi5/zXy/pOg1b209T3jb7Nv5wIs= -istio.io/gogo-genproto v0.0.0-20210113155706-4daf5697332f h1:9710FpGLvIJ1GGEbpuTh1smVBv+r8cJfR3G82ouSxIQ= -istio.io/gogo-genproto v0.0.0-20210113155706-4daf5697332f/go.mod h1:6BwTZRNbWS570wHX/uR1Wqk5e0157TofTAUMzT7N4+s= -k8s.io/api v0.18.1/go.mod h1:3My4jorQWzSs5a+l7Ge6JBbIxChLnY8HnuT58ZWolss= +istio.io/api v0.0.0-20220413180505-1574de06b7bd/go.mod h1:8ZZgyVgYrHhsFQarEgTfPnMGpdgTDZbxSjYhdwTUuAQ= +istio.io/api v0.0.0-20220516175159-89828b1f4baa h1:tAIVTavdLX+0T08yCR+UsQLozhLnRg5+/UNFZRjravI= +istio.io/api v0.0.0-20220516175159-89828b1f4baa/go.mod h1:00myJeQGWma4Y5pboJ+MM4P2uqEWulKA1duC8kYN5Wo= +istio.io/client-go v1.13.3 h1:xbEgTX4NRlvVRI/JsCmMI0ATvCc9P85HkQ20SphEGZ4= +istio.io/client-go v1.13.3/go.mod h1:DeT/l4yO+bwyv0ZgavSTj7BfkA2cTckHD0jtluwtXhE= +istio.io/gogo-genproto v0.0.0-20211208193508-5ab4acc9eb1e/go.mod h1:vJDAniIqryf/z///fgZqVPKJ7N2lBk7Gg8DCTB7oCfU= k8s.io/api v0.19.2/go.mod h1:IQpK0zFQ1xc5iNIQPqzgoOwuFugaYHK4iCknlAQP9nI= -k8s.io/api v0.20.2/go.mod h1:d7n6Ehyzx+S+cE3VhTGfVNNqtGc/oL9DCdYYahlurV8= k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg= -k8s.io/api v0.22.1 h1:ISu3tD/jRhYfSW8jI/Q1e+lRxkR7w9UwQEZ7FgslrwY= k8s.io/api v0.22.1/go.mod h1:bh13rkTp3F1XEaLGykbyRD2QaTTzPm0e/BMd8ptFONY= +k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg= +k8s.io/api v0.23.1 h1:ncu/qfBfUoClqwkTGbeRqqOqBCRoUAflMuOaOD7J0c8= +k8s.io/api v0.23.1/go.mod h1:WfXnOnwSqNtG62Y1CdjoMxh7r7u9QXGCkA1u0na2jgo= k8s.io/apiextensions-apiserver v0.19.2/go.mod h1:EYNjpqIAvNZe+svXVx9j4uBaVhTB4C94HkY3w058qcg= k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8LGDkprcd+KbsE= -k8s.io/apiextensions-apiserver v0.22.1 h1:YSJYzlFNFSfUle+yeEXX0lSQyLEoxoPJySRupepb0gE= -k8s.io/apiextensions-apiserver v0.22.1/go.mod h1:HeGmorjtRmRLE+Q8dJu6AYRoZccvCMsghwS8XTUYb2c= -k8s.io/apimachinery v0.18.1/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= +k8s.io/apiextensions-apiserver v0.23.0 h1:uii8BYmHYiT2ZTAJxmvc3X8UhNYMxl2A0z0Xq3Pm+WY= +k8s.io/apiextensions-apiserver v0.23.0/go.mod h1:xIFAEEDlAZgpVBl/1VSjGDmLoXAWRG40+GsWhKhAxY4= k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= -k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI= -k8s.io/apimachinery v0.22.1 h1:DTARnyzmdHMz7bFWFDDm22AM4pLWTQECMpRTFu2d2OM= k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= +k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFYc= +k8s.io/apimachinery v0.23.1 h1:sfBjlDFwj2onG0Ijx5C+SrAoeUscPrmghm7wHP+uXlo= +k8s.io/apimachinery v0.23.1/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno= k8s.io/apiserver v0.19.2/go.mod h1:FreAq0bJ2vtZFj9Ago/X0oNGC51GfubKK/ViOKfVAOA= k8s.io/apiserver v0.21.3/go.mod h1:eDPWlZG6/cCCMj/JBcEpDoK+I+6i3r9GsChYBHSbAzU= -k8s.io/apiserver v0.22.1/go.mod h1:2mcM6dzSt+XndzVQJX21Gx0/Klo7Aen7i0Ai6tIa400= -k8s.io/client-go v0.18.1/go.mod h1:iCikYRiXOj/yRRFE/aWqrpPtDt4P2JVWhtHkmESTcfY= +k8s.io/apiserver v0.23.0/go.mod h1:Cec35u/9zAepDPPFyT+UMrgqOCjgJ5qtfVJDxjZYmt4= k8s.io/client-go v0.19.2/go.mod h1:S5wPhCqyDNAlzM9CnEdgTGV4OqhsW3jGO1UM1epwfJA= k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU= -k8s.io/client-go v0.22.1 h1:jW0ZSHi8wW260FvcXHkIa0NLxFBQszTlhiAVsU5mopw= k8s.io/client-go v0.22.1/go.mod h1:BquC5A4UOo4qVDUtoc04/+Nxp1MeHcVc1HJm1KmG8kk= +k8s.io/client-go v0.23.0/go.mod h1:hrDnpnK1mSr65lHHcUuIZIXDgEbzc7/683c6hyG4jTA= +k8s.io/client-go v0.23.1 h1:Ma4Fhf/p07Nmj9yAB1H7UwbFHEBrSPg8lviR24U2GiQ= +k8s.io/client-go v0.23.1/go.mod h1:6QSI8fEuqD4zgFK0xbdwfB/PthBsIxCJMa3s17WlcO0= k8s.io/code-generator v0.19.2/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo= k8s.io/code-generator v0.22.0/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= -k8s.io/code-generator v0.22.1/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= +k8s.io/code-generator v0.23.0/go.mod h1:vQvOhDXhuzqiVfM/YHp+dmg10WDZCchJVObc9MvowsE= k8s.io/component-base v0.19.2/go.mod h1:g5LrsiTiabMLZ40AR6Hl45f088DevyGY+cCE2agEIVo= k8s.io/component-base v0.21.3/go.mod h1:kkuhtfEHeZM6LkX0saqSK8PbdO7A0HigUngmhhrwfGQ= -k8s.io/component-base v0.22.1 h1:SFqIXsEN3v3Kkr1bS6rstrs1wd45StJqbtgbQ4nRQdo= -k8s.io/component-base v0.22.1/go.mod h1:0D+Bl8rrnsPN9v0dyYvkqFfBeAd4u7n77ze+p8CMiPo= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/component-base v0.23.0 h1:UAnyzjvVZ2ZR1lF35YwtNY6VMN94WtOnArcXBu34es8= +k8s.io/component-base v0.23.0/go.mod h1:DHH5uiFvLC1edCpvcTDV++NKULdYYU6pR9Tt3HIKMKI= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201203183100-97869a43a9d9/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog v0.2.0 h1:0ElL0OHzF3N+OhoJTL0uca20SxtYt4X4+bzHeqrB83c= k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.10.0 h1:R2HDMDJsHVTHA2n4RjwbeYXdOcBymXdX/JRb1v0VGhE= k8s.io/klog/v2 v2.10.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= +k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= -k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20200912215256-4140de9c8800/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210820185131-d34e5cb4466e h1:ldQh+neBabomh7+89dTpiFAB8tGdfVmuIzAHbvtl+9I= k8s.io/utils v0.0.0-20210820185131-d34e5cb4466e/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE= +k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9/go.mod h1:dzAXnQbTRyDlZPJX2SUPEqvnB+j7AJjtlox7PEwigU0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.19/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.25/go.mod h1:Mlj9PNLmG9bZ6BHFwFKDo5afkpWyUISkb9Me0GnK66I= sigs.k8s.io/controller-runtime v0.7.2/go.mod h1:pJ3YBrJiAqMAZKi6UVGuE98ZrroV1p+pIhoHsMm9wdU= sigs.k8s.io/controller-runtime v0.9.6/go.mod h1:q6PpkM5vqQubEKUKOM6qr06oXGzOBcCby1DA9FbyZeA= -sigs.k8s.io/controller-runtime v0.10.0 h1:HgyZmMpjUOrtkaFtCnfxsR1bGRuFoAczSNbn2MoKj5U= -sigs.k8s.io/controller-runtime v0.10.0/go.mod h1:GCdh6kqV6IY4LK0JLwX0Zm6g233RtVGdb/f0+KSfprg= +sigs.k8s.io/controller-runtime v0.11.0 h1:DqO+c8mywcZLFJWILq4iktoECTyn30Bkj0CwgqMpZWQ= +sigs.k8s.io/controller-runtime v0.11.0/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA= sigs.k8s.io/controller-tools v0.6.2/go.mod h1:oaeGpjXn6+ZSEIQkUe/+3I40PNiDYp9aeawbt3xTgJ8= sigs.k8s.io/gateway-api v0.4.1 h1:Tof9/PNSZXyfDuTTe1XFvaTlvBRE6bKq1kmV6jj6rQE= sigs.k8s.io/gateway-api v0.4.1/go.mod h1:r3eiNP+0el+NTLwaTfOrCNXy8TukC+dIM3ggc+fbNWk= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.0/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/main.go b/main.go index a876ba4..f9720ad 100644 --- a/main.go +++ b/main.go @@ -29,6 +29,7 @@ import ( _ "k8s.io/client-go/plugin/pkg/client/auth" limitadorv1alpha1 "github.com/kuadrant/limitador-operator/api/v1alpha1" + istioextensionv1alpha1 "istio.io/client-go/pkg/apis/extensions/v1alpha1" istionetworkingv1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3" istiosecurityv1beta1 "istio.io/client-go/pkg/apis/security/v1beta1" k8sruntime "k8s.io/apimachinery/pkg/runtime" @@ -61,6 +62,7 @@ func init() { utilruntime.Must(istiosecurityv1beta1.AddToScheme(scheme)) utilruntime.Must(limitadorv1alpha1.AddToScheme(scheme)) utilruntime.Must(gatewayapiv1alpha2.AddToScheme(scheme)) + utilruntime.Must(istioextensionv1alpha1.AddToScheme(scheme)) // +kubebuilder:scaffold:scheme diff --git a/pkg/common/k8s_utils_test.go b/pkg/common/k8s_utils_test.go index 7d8d72a..aa01c72 100644 --- a/pkg/common/k8s_utils_test.go +++ b/pkg/common/k8s_utils_test.go @@ -1,3 +1,4 @@ +//go:build unit // +build unit package common diff --git a/pkg/istio/envoy_filters.go b/pkg/istio/envoy_filters.go deleted file mode 100644 index e481ec3..0000000 --- a/pkg/istio/envoy_filters.go +++ /dev/null @@ -1,423 +0,0 @@ -package istio - -import ( - "encoding/json" - "fmt" - - protobuftypes "github.com/gogo/protobuf/types" - istioapiv1alpha3 "istio.io/api/networking/v1alpha3" - istionetworkingv1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" - - apimv1alpha1 "github.com/kuadrant/kuadrant-controller/apis/apim/v1alpha1" - "github.com/kuadrant/kuadrant-controller/pkg/common" -) - -type HTTPFilterStage uint32 - -const ( - PreAuthStage HTTPFilterStage = iota - PostAuthStage - - PatchedLimitadorClusterName = "rate-limit-cluster" - PatchedWasmClusterName = "remote-wasm-cluster" -) - -const ( - EnvoysHTTPPortNumber = 8080 - EnvoysHTTPConnectionManagerName = "envoy.filters.network.http_connection_manager" -) - -type EnvoyFilterFactory struct { - ObjectName string - Namespace string - Patches []*istioapiv1alpha3.EnvoyFilter_EnvoyConfigObjectPatch - Labels map[string]string -} - -func (v *EnvoyFilterFactory) EnvoyFilter() *istionetworkingv1alpha3.EnvoyFilter { - return &istionetworkingv1alpha3.EnvoyFilter{ - TypeMeta: metav1.TypeMeta{ - Kind: "EnvoyFilter", - APIVersion: "networking.istio.io/v1alpha3", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: v.ObjectName, - Namespace: v.Namespace, - }, - Spec: istioapiv1alpha3.EnvoyFilter{ - WorkloadSelector: &istioapiv1alpha3.WorkloadSelector{ - Labels: v.Labels, - }, - ConfigPatches: v.Patches, - }, - } -} - -func LimitadorClusterEnvoyPatch() *istioapiv1alpha3.EnvoyFilter_EnvoyConfigObjectPatch { - // The patch defines the rate_limit_cluster, which provides the endpoint location of the external rate limit service. - - patchUnstructured := map[string]interface{}{ - "operation": "ADD", - "value": map[string]interface{}{ - "name": PatchedLimitadorClusterName, - "type": "STRICT_DNS", - "connect_timeout": "1s", - "lb_policy": "ROUND_ROBIN", - "http2_protocol_options": map[string]interface{}{}, - "load_assignment": map[string]interface{}{ - "cluster_name": PatchedLimitadorClusterName, - "endpoints": []map[string]interface{}{ - { - "lb_endpoints": []map[string]interface{}{ - { - "endpoint": map[string]interface{}{ - "address": map[string]interface{}{ - "socket_address": map[string]interface{}{ - "address": common.LimitadorServiceClusterHost, - "port_value": common.LimitadorServiceGrpcPort, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - patchRaw, _ := json.Marshal(patchUnstructured) - - patch := &istioapiv1alpha3.EnvoyFilter_Patch{} - err := patch.UnmarshalJSON(patchRaw) - if err != nil { - panic(err) - } - - return &istioapiv1alpha3.EnvoyFilter_EnvoyConfigObjectPatch{ - ApplyTo: istioapiv1alpha3.EnvoyFilter_CLUSTER, - Match: &istioapiv1alpha3.EnvoyFilter_EnvoyConfigObjectMatch{ - ObjectTypes: &istioapiv1alpha3.EnvoyFilter_EnvoyConfigObjectMatch_Cluster{ - Cluster: &istioapiv1alpha3.EnvoyFilter_ClusterMatch{ - Service: common.LimitadorServiceClusterHost, - }, - }, - }, - Patch: patch, - } -} - -func WasmClusterEnvoyPatch() *istioapiv1alpha3.EnvoyFilter_EnvoyConfigObjectPatch { - patchUnstructured := map[string]interface{}{ - "operation": "ADD", - "value": map[string]interface{}{ - "name": PatchedWasmClusterName, - "type": "STRICT_DNS", - "connect_timeout": "1s", - "load_assignment": map[string]interface{}{ - "cluster_name": PatchedWasmClusterName, - "endpoints": []map[string]interface{}{ - { - "lb_endpoints": []map[string]interface{}{ - { - "endpoint": map[string]interface{}{ - "address": map[string]interface{}{ - "socket_address": map[string]interface{}{ - "address": "raw.githubusercontent.com", - "port_value": 443, - }, - }, - }, - }, - }, - }, - }, - }, - "dns_lookup_family": "V4_ONLY", - "transport_socket": map[string]interface{}{ - "name": "envoy.transport_sockets.tls", - "typed_config": map[string]interface{}{ - "@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext", - "sni": "raw.githubusercontent.com", - }, - }, - }, - } - - patchRaw, _ := json.Marshal(patchUnstructured) - - patch := &istioapiv1alpha3.EnvoyFilter_Patch{} - err := patch.UnmarshalJSON(patchRaw) - if err != nil { - panic(err) - } - return &istioapiv1alpha3.EnvoyFilter_EnvoyConfigObjectPatch{ - ApplyTo: istioapiv1alpha3.EnvoyFilter_CLUSTER, - Match: &istioapiv1alpha3.EnvoyFilter_EnvoyConfigObjectMatch{ - Context: istioapiv1alpha3.EnvoyFilter_GATEWAY, - }, - Patch: patch, - } -} - -// EnvoyFilterRatelimitsUnstructured returns "rate_limits" envoy filter patch format from kuadrant rate limits -func EnvoyFilterRatelimitsUnstructured(rateLimits []*apimv1alpha1.RateLimit) []map[string]interface{} { - envoyRateLimits := make([]map[string]interface{}, 0) - for _, rateLimit := range rateLimits { - if rateLimit.Stage == apimv1alpha1.RateLimitStageBOTH { - // Apply same actions to both stages - stages := []apimv1alpha1.RateLimitStage{ - apimv1alpha1.RateLimitStagePREAUTH, - apimv1alpha1.RateLimitStagePOSTAUTH, - } - - for _, stage := range stages { - envoyRateLimit := map[string]interface{}{ - "stage": apimv1alpha1.RateLimitStageValue[stage], - "actions": rateLimit.Actions, - } - envoyRateLimits = append(envoyRateLimits, envoyRateLimit) - } - } else { - envoyRateLimit := map[string]interface{}{ - "stage": apimv1alpha1.RateLimitStageValue[rateLimit.Stage], - "actions": rateLimit.Actions, - } - envoyRateLimits = append(envoyRateLimits, envoyRateLimit) - } - } - - return envoyRateLimits -} - -func WASMEnvoyFilterKey(gwKey client.ObjectKey) client.ObjectKey { - return client.ObjectKey{ - Name: fmt.Sprintf("kuadrant-%s-wasm-ratelimits", gwKey.Name), - Namespace: gwKey.Namespace, - } -} - -// WASMEnvoyFilter returns desired WASM envoy filter -// - Pre-Authorization ratelimit wasm filter -// - Post-Authorization ratelimit wasm filter -// - Limitador cluster (tmp-fix) -// - Wasm cluster -func WASMEnvoyFilter(rlp *apimv1alpha1.RateLimitPolicy, gwKey client.ObjectKey, gwLabels map[string]string, hosts []gatewayapiv1alpha2.Hostname) (*istionetworkingv1alpha3.EnvoyFilter, error) { - rlpKey := client.ObjectKeyFromObject(rlp) - preAuthPluginPolicy := PluginPolicyFromRateLimitPolicy(rlp, apimv1alpha1.RateLimitStagePREAUTH, hosts) - postAuthPluginPolicy := PluginPolicyFromRateLimitPolicy(rlp, apimv1alpha1.RateLimitStagePOSTAUTH, hosts) - - finalPatches := []*istioapiv1alpha3.EnvoyFilter_EnvoyConfigObjectPatch{} - - preAuthPluginConfig := PluginConfig{ - FailureModeDeny: true, - PluginPolicies: map[string]PluginPolicy{ - rlpKey.String(): *preAuthPluginPolicy, - }, - } - preAuthJSON, err := json.Marshal(preAuthPluginConfig) - if err != nil { - return nil, fmt.Errorf("failed to marshall preauth plugin config into json") - } - - postAuthPluginConfig := PluginConfig{ - FailureModeDeny: true, - PluginPolicies: map[string]PluginPolicy{ - rlpKey.String(): *postAuthPluginPolicy, - }, - } - postAuthJSON, err := json.Marshal(postAuthPluginConfig) - if err != nil { - return nil, fmt.Errorf("failed to marshall preauth plugin config into json") - } - - patchUnstructured := map[string]interface{}{ - "operation": "INSERT_FIRST", // preauth should be the first filter in the chain - "value": map[string]interface{}{ - "name": "envoy.filters.http.preauth.wasm", - "typed_config": map[string]interface{}{ - "@type": "type.googleapis.com/udpa.type.v1.TypedStruct", - "typeUrl": "type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm", - "value": map[string]interface{}{ - "config": map[string]interface{}{ - "configuration": map[string]interface{}{ - "@type": "type.googleapis.com/google.protobuf.StringValue", - "value": string(preAuthJSON), - }, - "name": "preauth-wasm", - "vm_config": map[string]interface{}{ - "code": map[string]interface{}{ - "remote": map[string]interface{}{ - "http_uri": map[string]interface{}{ - "uri": "https://raw.githubusercontent.com/rahulanand16nov/wasm-shim/new-api/deploy/wasm_shim.wasm", - "cluster": PatchedWasmClusterName, - "timeout": "10s", - }, - "sha256": "de54c4d2ce405425515e14e1cc45285acf632c490de1f5f55c00e2acb832c89e", - "retry_policy": map[string]interface{}{ - "num_retries": 10, - }, - }, - }, - "allow_precompiled": true, - "runtime": "envoy.wasm.runtime.v8", - }, - }, - }, - }, - }, - } - - patchRaw, _ := json.Marshal(patchUnstructured) - prePatch := istioapiv1alpha3.EnvoyFilter_Patch{} - if err := prePatch.UnmarshalJSON(patchRaw); err != nil { - return nil, err - } - - postPatch := prePatch.DeepCopy() - - // update filter name - postPatch.Value.Fields["name"] = &protobuftypes.Value{ - Kind: &protobuftypes.Value_StringValue{ - StringValue: "envoy.filters.http.postauth.wasm", - }, - } - - // update operation for postauth filter - postPatch.Operation = istioapiv1alpha3.EnvoyFilter_Patch_INSERT_BEFORE - - pluginConfig := postPatch.Value.Fields["typed_config"].GetStructValue().Fields["value"].GetStructValue().Fields["config"] - - // update plugin config for postauth filter - pluginConfig.GetStructValue().Fields["configuration"].GetStructValue().Fields["value"] = &protobuftypes.Value{ - Kind: &protobuftypes.Value_StringValue{ - StringValue: string(postAuthJSON), - }, - } - - // update plugin name - pluginConfig.GetStructValue().Fields["name"] = &protobuftypes.Value{ - Kind: &protobuftypes.Value_StringValue{ - StringValue: "postauth-wasm", - }, - } - - preAuthFilterPatch := &istioapiv1alpha3.EnvoyFilter_EnvoyConfigObjectPatch{ - ApplyTo: istioapiv1alpha3.EnvoyFilter_HTTP_FILTER, - Match: &istioapiv1alpha3.EnvoyFilter_EnvoyConfigObjectMatch{ - Context: istioapiv1alpha3.EnvoyFilter_GATEWAY, - ObjectTypes: &istioapiv1alpha3.EnvoyFilter_EnvoyConfigObjectMatch_Listener{ - Listener: &istioapiv1alpha3.EnvoyFilter_ListenerMatch{ - PortNumber: EnvoysHTTPPortNumber, // Kuadrant-gateway listens on this port by default - FilterChain: &istioapiv1alpha3.EnvoyFilter_ListenerMatch_FilterChainMatch{ - Filter: &istioapiv1alpha3.EnvoyFilter_ListenerMatch_FilterMatch{ - Name: EnvoysHTTPConnectionManagerName, - }, - }, - }, - }, - }, - Patch: &prePatch, - } - - postAuthFilterPatch := preAuthFilterPatch.DeepCopy() - postAuthFilterPatch.Patch = postPatch - - // postauth filter should be injected just before the router filter - postAuthFilterPatch.Match.ObjectTypes = &istioapiv1alpha3.EnvoyFilter_EnvoyConfigObjectMatch_Listener{ - Listener: &istioapiv1alpha3.EnvoyFilter_ListenerMatch{ - PortNumber: EnvoysHTTPPortNumber, - FilterChain: &istioapiv1alpha3.EnvoyFilter_ListenerMatch_FilterChainMatch{ - Filter: &istioapiv1alpha3.EnvoyFilter_ListenerMatch_FilterMatch{ - Name: EnvoysHTTPConnectionManagerName, - SubFilter: &istioapiv1alpha3.EnvoyFilter_ListenerMatch_SubFilterMatch{ - Name: "envoy.filters.http.router", - }, - }, - }, - }, - } - - // since it's the first time, add the Limitador and Wasm cluster into the patches - finalPatches = append(finalPatches, preAuthFilterPatch, postAuthFilterPatch, - LimitadorClusterEnvoyPatch(), WasmClusterEnvoyPatch()) - - wasmKey := WASMEnvoyFilterKey(gwKey) - factory := EnvoyFilterFactory{ - ObjectName: wasmKey.Name, - Namespace: wasmKey.Namespace, - Patches: finalPatches, - Labels: gwLabels, - } - return factory.EnvoyFilter(), nil -} - -func WASMEnvoyFilterPluginMutator(existingObj, desiredObj client.Object) (bool, error) { - existing, ok := existingObj.(*istionetworkingv1alpha3.EnvoyFilter) - if !ok { - return false, fmt.Errorf("%T is not a *istionetworkingv1alpha3.EnvoyFilter", existingObj) - } - desired, ok := desiredObj.(*istionetworkingv1alpha3.EnvoyFilter) - if !ok { - return false, fmt.Errorf("%T is not a *istionetworkingv1alpha3.EnvoyFilter", desiredObj) - } - - update := false - - // first patch is PRE - // second patch is POST - for idx := 0; idx < 2; idx++ { - existingPatch := existing.Spec.ConfigPatches[idx] - desiredPatch := desired.Spec.ConfigPatches[idx] - - // Deserialize existing plugin config - // existingPluginConfigValue is a pointer to Value. It can me modified. - existingConfigFields := existingPatch.Patch.Value.Fields["typed_config"]. - GetStructValue().Fields["value"].GetStructValue().Fields["config"].GetStructValue(). - Fields["configuration"].GetStructValue().Fields - existingPluginConfigValue := existingConfigFields["value"] - existingPluginConfigStr := existingPluginConfigValue.GetStringValue() - existingPluginConfig := &PluginConfig{} - if err := json.Unmarshal([]byte(existingPluginConfigStr), existingPluginConfig); err != nil { - return false, fmt.Errorf("failed to unmarshal existing plugin config: %w", err) - } - - // Deserialize desired plugin config - desiredPluginConfigStr := desiredPatch.Patch.Value.Fields["typed_config"]. - GetStructValue().Fields["value"].GetStructValue().Fields["config"].GetStructValue(). - Fields["configuration"].GetStructValue().Fields["value"].GetStringValue() - - desiredPluginConfig := &PluginConfig{} - if err := json.Unmarshal([]byte(desiredPluginConfigStr), desiredPluginConfig); err != nil { - return false, fmt.Errorf("failed to unmarshal desired plugin config: %w", err) - } - if len(desiredPluginConfig.PluginPolicies) == 0 { - return false, fmt.Errorf("desired plugin config has empty plugin policies") - } - if len(desiredPluginConfig.PluginPolicies) > 1 { - return false, fmt.Errorf("desired plugin config has multiple policies") - } - - patchUpdate := false - MergeMapStringPluginPolicy(&patchUpdate, &existingPluginConfig.PluginPolicies, desiredPluginConfig.PluginPolicies) - - if patchUpdate { - update = true - newExistingPluginConfigSerialized, err := json.Marshal(existingPluginConfig) - if err != nil { - return false, fmt.Errorf("failed to marshall new existing plugin config into json: %w", err) - } - // Update existing envoyfilter patch value - existingConfigFields["value"] = &protobuftypes.Value{ - Kind: &protobuftypes.Value_StringValue{ - StringValue: string(newExistingPluginConfigSerialized), - }, - } - } - } - - return update, nil -} diff --git a/pkg/istio/wasm.go b/pkg/istio/wasm.go index 12505fc..02471e4 100644 --- a/pkg/istio/wasm.go +++ b/pkg/istio/wasm.go @@ -7,6 +7,8 @@ import ( gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" ) +const PatchedLimitadorClusterName = "rate-limit-cluster" + // wasm-shim API structs type Rule struct { Operations []*apimv1alpha1.Operation `json:"operations"` diff --git a/pkg/istio/wasm_plugins.go b/pkg/istio/wasm_plugins.go new file mode 100644 index 0000000..9ed79da --- /dev/null +++ b/pkg/istio/wasm_plugins.go @@ -0,0 +1,148 @@ +package istio + +import ( + "encoding/json" + "fmt" + "strings" + + _struct "github.com/golang/protobuf/ptypes/struct" + apimv1alpha1 "github.com/kuadrant/kuadrant-controller/apis/apim/v1alpha1" + istioapiv1alpha1 "istio.io/api/extensions/v1alpha1" + "istio.io/api/type/v1beta1" + istioextensionv1alpha3 "istio.io/client-go/pkg/apis/extensions/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" +) + +type WasmPluginFactory struct { + ObjectName string + Namespace string + Phase istioapiv1alpha1.PluginPhase + Config *_struct.Struct + Labels map[string]string +} + +func (v *WasmPluginFactory) WasmPlugin() *istioextensionv1alpha3.WasmPlugin { + return &istioextensionv1alpha3.WasmPlugin{ + TypeMeta: metav1.TypeMeta{ + Kind: "WasmPlugin", + APIVersion: "extensions.istio.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: v.ObjectName, + Namespace: v.Namespace, + }, + Spec: istioapiv1alpha1.WasmPlugin{ + Selector: &v1beta1.WorkloadSelector{ + MatchLabels: v.Labels, + }, + Url: "oci://quay.io/rahanand/wasm-shim:latest", // TODO: take this from Environment. + PluginConfig: v.Config, + Phase: v.Phase, + }, + } +} + +func WASMPluginKey(gwKey client.ObjectKey, stage apimv1alpha1.RateLimitStage) client.ObjectKey { + stageStr := strings.ToLower(string(stage)) + return client.ObjectKey{ + Name: fmt.Sprintf("kuadrant-%s-wasm-%s", gwKey.Name, stageStr), + Namespace: gwKey.Namespace, + } +} + +func PluginConfigToWasmPluginStruct(config *PluginConfig) (*_struct.Struct, error) { + pluginConfigJSON, err := json.Marshal(config) + if err != nil { + return nil, err + } + + pluginConfigStruct := &_struct.Struct{} + if err := pluginConfigStruct.UnmarshalJSON(pluginConfigJSON); err != nil { + return nil, err + } + return pluginConfigStruct, nil +} + +func WasmPlugins(rlp *apimv1alpha1.RateLimitPolicy, gwKey client.ObjectKey, gwLabels map[string]string, hosts []gatewayapiv1alpha2.Hostname) ([]*istioextensionv1alpha3.WasmPlugin, error) { + rlpKey := client.ObjectKeyFromObject(rlp) + + stagePhaseMapping := map[apimv1alpha1.RateLimitStage]istioapiv1alpha1.PluginPhase{ + apimv1alpha1.RateLimitStagePREAUTH: istioapiv1alpha1.PluginPhase_AUTHN, + apimv1alpha1.RateLimitStagePOSTAUTH: istioapiv1alpha1.PluginPhase_STATS, + } + + wasmPlugins := []*istioextensionv1alpha3.WasmPlugin{} + for stage, phase := range stagePhaseMapping { + pluginPolicy := PluginPolicyFromRateLimitPolicy(rlp, stage, hosts) + pluginConfig := &PluginConfig{ + FailureModeDeny: true, + PluginPolicies: map[string]PluginPolicy{ + rlpKey.String(): *pluginPolicy, + }, + } + + pluginConfigStruct, err := PluginConfigToWasmPluginStruct(pluginConfig) + if err != nil { + return nil, err + } + + pluginKey := WASMPluginKey(gwKey, stage) + pluginFactory := WasmPluginFactory{ + ObjectName: pluginKey.Name, + Namespace: pluginKey.Namespace, + Phase: phase, + Config: pluginConfigStruct, + Labels: gwLabels, + } + + wasmPlugins = append(wasmPlugins, pluginFactory.WasmPlugin()) + } + + return wasmPlugins, nil +} + +func WASMPluginMutator(existingObj, desiredObj client.Object) (bool, error) { + update := false + existing, ok := existingObj.(*istioextensionv1alpha3.WasmPlugin) + if !ok { + return false, fmt.Errorf("%T is not a *istioextensionv1alpha3.WasmPlugin", existingObj) + } + desired, ok := desiredObj.(*istioextensionv1alpha3.WasmPlugin) + if !ok { + return false, fmt.Errorf("%T is not a *istioextensionv1alpha3.WasmPlugin", desiredObj) + } + + // Deserialize config into PluginConfig struct + existingConfigJSON, err := existing.Spec.PluginConfig.MarshalJSON() + if err != nil { + return false, err + } + existingPluginConfig := &PluginConfig{} + if err := json.Unmarshal(existingConfigJSON, existingPluginConfig); err != nil { + return false, err + } + + desiredConfigJSON, err := desired.Spec.PluginConfig.MarshalJSON() + if err != nil { + return false, err + } + desiredPluginConfig := &PluginConfig{} + if err := json.Unmarshal(desiredConfigJSON, desiredPluginConfig); err != nil { + return false, err + } + + patchUpdate := false + MergeMapStringPluginPolicy(&patchUpdate, &existingPluginConfig.PluginPolicies, desiredPluginConfig.PluginPolicies) + + if patchUpdate { + update = true + finalPluginConfig, err := PluginConfigToWasmPluginStruct(existingPluginConfig) + if err != nil { + return false, err + } + existing.Spec.PluginConfig = finalPluginConfig + } + return update, nil +} diff --git a/pkg/log/log.go b/pkg/log/log.go index 657605a..b5c0d4f 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -32,7 +32,7 @@ import ( var ( // Log is the base logger - Log logr.Logger = ctrllog.NullLogger{} + Log logr.Logger = logr.New(ctrllog.NullLogSink{}) ) // Level configures the verbosity of the logging. diff --git a/pkg/reconcilers/base_reconciler.go b/pkg/reconcilers/base_reconciler.go index 0bccc99..876e84a 100644 --- a/pkg/reconcilers/base_reconciler.go +++ b/pkg/reconcilers/base_reconciler.go @@ -137,31 +137,31 @@ func (b *BaseReconciler) ReconcileResource(ctx context.Context, obj, desired cli } func (b *BaseReconciler) GetResource(ctx context.Context, objKey types.NamespacedName, obj client.Object) error { - logger := logr.FromContext(ctx) + logger, _ := logr.FromContext(ctx) logger.Info("get object", "kind", strings.Replace(fmt.Sprintf("%T", obj), "*", "", 1), "name", objKey.Name, "namespace", objKey.Namespace) return b.Client().Get(ctx, objKey, obj) } func (b *BaseReconciler) CreateResource(ctx context.Context, obj client.Object) error { - logger := logr.FromContext(ctx) + logger, _ := logr.FromContext(ctx) logger.Info("create object", "kind", strings.Replace(fmt.Sprintf("%T", obj), "*", "", 1), "name", obj.GetName(), "namespace", obj.GetNamespace()) return b.Client().Create(ctx, obj) } func (b *BaseReconciler) UpdateResource(ctx context.Context, obj client.Object) error { - logger := logr.FromContext(ctx) + logger, _ := logr.FromContext(ctx) logger.Info("update object", "kind", strings.Replace(fmt.Sprintf("%T", obj), "*", "", 1), "name", obj.GetName(), "namespace", obj.GetNamespace()) return b.Client().Update(ctx, obj) } func (b *BaseReconciler) DeleteResource(ctx context.Context, obj client.Object, options ...client.DeleteOption) error { - logger := logr.FromContext(ctx) + logger, _ := logr.FromContext(ctx) logger.Info("delete object", "kind", strings.Replace(fmt.Sprintf("%T", obj), "*", "", 1), "name", obj.GetName(), "namespace", obj.GetNamespace()) return b.Client().Delete(ctx, obj, options...) } func (b *BaseReconciler) UpdateResourceStatus(ctx context.Context, obj client.Object) error { - logger := logr.FromContext(ctx) + logger, _ := logr.FromContext(ctx) logger.Info("update object status", "kind", strings.Replace(fmt.Sprintf("%T", obj), "*", "", 1), "name", obj.GetName(), "namespace", obj.GetNamespace()) return b.Client().Status().Update(ctx, obj) } diff --git a/utils/local-deployment/deploy-kuadrant-deps.sh b/utils/local-deployment/deploy-kuadrant-deps.sh index 6406683..6db6bbb 100755 --- a/utils/local-deployment/deploy-kuadrant-deps.sh +++ b/utils/local-deployment/deploy-kuadrant-deps.sh @@ -28,6 +28,7 @@ kubectl apply -f utils/local-deployment/istio-manifests/autogenerated/Base/Base. kubectl apply -f utils/local-deployment/istio-manifests/autogenerated/Base/Pilot/Pilot.yaml kubectl apply -f utils/local-deployment/istio-manifests/autogenerated/Base/Pilot/IngressGateways/IngressGateways.yaml kubectl apply -n "${KUADRANT_NAMESPACE}" -f utils/local-deployment/istio-manifests/kuadrant-gateway.yaml +kubectl apply -n "${KUADRANT_NAMESPACE}" -f utils/local-deployment/limitador-cluster.yaml echo "Installing Gateway API CRDs and Applying the Gateway resource" kubectl apply -f utils/local-deployment/gatewayapi-manifests/autogenerated/Base.yaml diff --git a/utils/local-deployment/limitador-cluster.yaml b/utils/local-deployment/limitador-cluster.yaml new file mode 100644 index 0000000..c6885e1 --- /dev/null +++ b/utils/local-deployment/limitador-cluster.yaml @@ -0,0 +1,27 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: kuadrant-limitador-cluster-entry +spec: + configPatches: + - applyTo: CLUSTER + match: + cluster: + service: limitador.kuadrant-system.svc.cluster.local + patch: + operation: ADD + value: + connect_timeout: 1s + http2_protocol_options: {} + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: rate-limit-cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: limitador.kuadrant-system.svc.cluster.local + port_value: 8081 + name: rate-limit-cluster + type: STRICT_DNS \ No newline at end of file