From 309eaabdd2b05b0c5113ade4c88dbfc887a7512f Mon Sep 17 00:00:00 2001 From: yweng14 Date: Fri, 6 Dec 2024 13:27:08 -0500 Subject: [PATCH] add LLMBackendTrafficPolicy Signed-off-by: yweng14 --- Makefile | 2 +- api/v1alpha1/api.go | 202 +++++++++++++++ api/v1alpha1/zz_generated.deepcopy.go | 243 ++++++++++++++++++ ...voyproxy.io_llmbackendtrafficpolicies.yaml | 183 +++++++++++++ 4 files changed, 629 insertions(+), 1 deletion(-) create mode 100644 manifests/charts/ai-gateway-helm/crds/aigateway.envoyproxy.io_llmbackendtrafficpolicies.yaml diff --git a/Makefile b/Makefile index 53aebec9..dfc51e7c 100644 --- a/Makefile +++ b/Makefile @@ -88,7 +88,7 @@ test-cel: envtest apigen format # To build for multiple platforms, set the GOOS_LIST and GOARCH_LIST variables. # # Example: -# - `make build.controler GOOS_LIST="linux darwin" GOARCH_LIST="amd64 arm64"` +# - `make build.controller GOOS_LIST="linux darwin" GOARCH_LIST="amd64 arm64"` GOOS_LIST ?= $(shell go env GOOS) GOARCH_LIST ?= $(shell go env GOARCH) .PHONY: build.% diff --git a/api/v1alpha1/api.go b/api/v1alpha1/api.go index 0d5aa04f..9f0ead71 100644 --- a/api/v1alpha1/api.go +++ b/api/v1alpha1/api.go @@ -123,3 +123,205 @@ const ( // https://docs.aws.amazon.com/bedrock/latest/APIReference/API_Operations_Amazon_Bedrock_Runtime.html APISchemaAWSBedrock APISchema = "AWSBedrock" ) + +// +kubebuilder:object:root=true + +// LLMBackendTrafficPolicy controls the flow of traffic to the backend. +type LLMBackendTrafficPolicy struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + // Spec defines the details of the LLMBackend traffic policy. + Spec LLMBackendTrafficPolicySpec `json:"spec,omitempty"` +} + +// +kubebuilder:object:root=true + +// LLMBackendTrafficPolicyList contains a list of LLMBackendTrafficPolicy +type LLMBackendTrafficPolicyList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []LLMBackendTrafficPolicy `json:"items"` +} + +// LLMBackendTrafficPolicySpec defines the details of llm backend traffic policy +// like rateLimit, timeout etc. +type LLMBackendTrafficPolicySpec struct { + // BackendRefs lists the LLMBackends that this traffic policy will apply + // The namespace is "local", i.e. the same namespace as the LLMRoute. + // + BackendRef LLMBackendLocalRef `json:"backendRef,omitempty"` + + // RateLimit defines the rate limit policy. + RateLimit *LLMTrafficPolicyRateLimit `json:"rateLimit,omitempty"` +} + +type LLMTrafficPolicyRateLimit struct { + // Rules defines the rate limit rules. + Rules []LLMTrafficPolicyRateLimitRule `json:"rules,omitempty"` +} + +// LLMTrafficPolicyRateLimitRule defines the details of the rate limit policy. +type LLMTrafficPolicyRateLimitRule struct { + // Headers is a list of request headers to match. Multiple header values are ANDed together, + // meaning, a request MUST match all the specified headers. + // At least one of headers or sourceCIDR condition must be specified. + Headers []LLMPolicyRateLimitHeaderMatch `json:"headers,omitempty"` + // Metadata is a list of metadata to match. Multiple metadata values are ANDed together, + Metadata []LLMPolicyRateLimitMetadataMatch `json:"metadata,omitempty"` + // Limits holds the rate limit values. + // This limit is applied for traffic flows when the selectors + // compute to True, causing the request to be counted towards the limit. + // The limit is enforced and the request is ratelimited, i.e. a response with + // 429 HTTP status code is sent back to the client when + // the selected requests have reached the limit. + // + // +kubebuilder:validation:MinItems=1 + Limits []LLMPolicyRateLimitValue `json:"limits"` +} + +type LLMPolicyRateLimitModelNameMatch struct { + // Type specifies how to match against the value of the model name. + // Only "Exact" and "Distinct" are supported. + // +kubebuilder:validation:Enum=Exact;Distinct + Type LLMPolicyRateLimitStringMatchType `json:"type"` + // Value specifies the value of the model name base on the match Type. + // It is ignored if the match Type is "Distinct". + // + // +optional + // +kubebuilder:validation:MaxLength=1024 + Value *string `json:"value"` +} + +// LLMPolicyRateLimitHeaderMatch defines the match attributes within the HTTP Headers of the request. +type LLMPolicyRateLimitHeaderMatch struct { + // Type specifies how to match against the value of the header. + Type LLMPolicyRateLimitStringMatchType `json:"type"` + + // Name of the HTTP header. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=256 + Name string `json:"name"` + + // Value within the HTTP header. Due to the + // case-insensitivity of header names, "foo" and "Foo" are considered equivalent. + // Do not set this field when Type="Distinct", implying matching on any/all unique + // values within the header. + // + // +optional + // +kubebuilder:validation:MaxLength=1024 + Value *string `json:"value,omitempty"` +} + +// LLMPolicyRateLimitStringMatchType specifies the semantics of how string values should be compared. +// Valid LLMPolicyRateLimitStringMatchType values are "Exact", "RegularExpression", and "Distinct". +// +// +kubebuilder:validation:Enum=Exact;RegularExpression;Distinct +type LLMPolicyRateLimitStringMatchType string + +// HeaderMatchType constants. +const ( + // HeaderMatchExact matches the exact value of the Value field against the value of + // the specified HTTP Header. + HeaderMatchExact LLMPolicyRateLimitStringMatchType = "Exact" + // HeaderMatchRegularExpression matches a regular expression against the value of the + // specified HTTP Header. The regex string must adhere to the syntax documented in + // https://github.com/google/re2/wiki/Syntax. + HeaderMatchRegularExpression LLMPolicyRateLimitStringMatchType = "RegularExpression" + // HeaderMatchDistinct matches any and all possible unique values encountered in the + // specified HTTP Header. Note that each unique value will receive its own rate limit + // bucket. + // Note: This is only supported for Global Rate Limits. + HeaderMatchDistinct LLMPolicyRateLimitStringMatchType = "Distinct" +) + +// LLMPolicyRateLimitMetadataMatch defines the match attributes within the metadata from dynamic or route entry. +// The match will be ignored if the metadata is not present. +type LLMPolicyRateLimitMetadataMatch struct { + // Type specifies the type of metadata to match. + // + // +kubebuilder:default=Dynamic + Type LLMPolicyRateLimitMetadataMatchMetadataType `json:"type"` + // Name specifies the key of the metadata to match. + Name string `json:"name"` + // Paths specifies the value of the metadata to match. + // +optional + // +kubebuilder:validation:MaxItems=32 + Paths []string `json:"paths,omitempty"` + // DefaultValue specifies an optional value to use if “metadata“ is empty. + // Default value is "unknown". + // + // +optional + DefaultValue *string `json:"defaultValue,omitempty"` +} + +// LLMPolicyRateLimitMetadataMatchMetadataType specifies the type of metadata to match. +// +// +kubebuilder:validation:Enum=Dynamic;RouteEntry +type LLMPolicyRateLimitMetadataMatchMetadataType string + +const ( + // MetadataTypeDynamic specifies that the source of metadata is dynamic. + MetadataTypeDynamic LLMPolicyRateLimitMetadataMatchMetadataType = "Dynamic" +) + +// LLMPolicyRateLimitValue defines the limits for rate limiting. +type LLMPolicyRateLimitValue struct { + // Type specifies the type of rate limit. + // + // +kubebuilder:default=Request + Type LLMPolicyRateLimitType `json:"type"` + // Quantity specifies the number of requests or tokens allowed in the given interval. + Quantity uint `json:"quantity"` + // Unit specifies the interval for the rate limit. + // + // +kubebuilder:default=Minute + Unit LLMPolicyRateLimitUnit `json:"unit"` +} + +// LLMPolicyRateLimitType specifies the type of rate limit. +// Valid RateLimitType values are "Request" and "Token". +// +// +kubebuilder:validation:Enum=Request;Token +type LLMPolicyRateLimitType string + +const ( + // RateLimitTypeRequest specifies the rate limit to be based on the number of requests. + RateLimitTypeRequest LLMPolicyRateLimitType = "Request" + // RateLimitTypeToken specifies the rate limit to be based on the number of tokens. + RateLimitTypeToken LLMPolicyRateLimitType = "Token" +) + +// LLMPolicyRateLimitUnit specifies the intervals for setting rate limits. +// Valid RateLimitUnit values are "Second", "Minute", "Hour", and "Day". +// +// +kubebuilder:validation:Enum=Second;Minute;Hour;Day +type LLMPolicyRateLimitUnit string + +// RateLimitUnit constants. +const ( + // RateLimitUnitSecond specifies the rate limit interval to be 1 second. + RateLimitUnitSecond LLMPolicyRateLimitUnit = "Second" + + // RateLimitUnitMinute specifies the rate limit interval to be 1 minute. + RateLimitUnitMinute LLMPolicyRateLimitUnit = "Minute" + + // RateLimitUnitHour specifies the rate limit interval to be 1 hour. + RateLimitUnitHour LLMPolicyRateLimitUnit = "Hour" + + // RateLimitUnitDay specifies the rate limit interval to be 1 day. + RateLimitUnitDay LLMPolicyRateLimitUnit = "Day" +) + +// +kubebuilder:validation:XValidation:rule="has(self.group) ? self.group == 'gateway.networking.k8s.io' : true ", message="group must be gateway.networking.k8s.io" +type TargetSelector struct { + // Group is the group that this selector targets. Defaults to gateway.networking.k8s.io + // + // +kubebuilder:default:="gateway.networking.k8s.io" + Group *gwapiv1a2.Group `json:"group,omitempty"` + + // Kind is the resource kind that this selector targets. + Kind gwapiv1a2.Kind `json:"kind"` + + // MatchLabels are the set of label selectors for identifying the targeted resource + MatchLabels map[string]string `json:"matchLabels"` +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index b95cd193..0e033c28 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -6,6 +6,7 @@ package v1alpha1 import ( runtime "k8s.io/apimachinery/pkg/runtime" + v1 "sigs.k8s.io/gateway-api/apis/v1" "sigs.k8s.io/gateway-api/apis/v1alpha2" ) @@ -113,6 +114,165 @@ func (in *LLMBackendSpec) DeepCopy() *LLMBackendSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMBackendTrafficPolicy) DeepCopyInto(out *LLMBackendTrafficPolicy) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMBackendTrafficPolicy. +func (in *LLMBackendTrafficPolicy) DeepCopy() *LLMBackendTrafficPolicy { + if in == nil { + return nil + } + out := new(LLMBackendTrafficPolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *LLMBackendTrafficPolicy) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMBackendTrafficPolicyList) DeepCopyInto(out *LLMBackendTrafficPolicyList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]LLMBackendTrafficPolicy, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMBackendTrafficPolicyList. +func (in *LLMBackendTrafficPolicyList) DeepCopy() *LLMBackendTrafficPolicyList { + if in == nil { + return nil + } + out := new(LLMBackendTrafficPolicyList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *LLMBackendTrafficPolicyList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMBackendTrafficPolicySpec) DeepCopyInto(out *LLMBackendTrafficPolicySpec) { + *out = *in + out.BackendRef = in.BackendRef + if in.RateLimit != nil { + in, out := &in.RateLimit, &out.RateLimit + *out = new(LLMTrafficPolicyRateLimit) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMBackendTrafficPolicySpec. +func (in *LLMBackendTrafficPolicySpec) DeepCopy() *LLMBackendTrafficPolicySpec { + if in == nil { + return nil + } + out := new(LLMBackendTrafficPolicySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMPolicyRateLimitHeaderMatch) DeepCopyInto(out *LLMPolicyRateLimitHeaderMatch) { + *out = *in + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMPolicyRateLimitHeaderMatch. +func (in *LLMPolicyRateLimitHeaderMatch) DeepCopy() *LLMPolicyRateLimitHeaderMatch { + if in == nil { + return nil + } + out := new(LLMPolicyRateLimitHeaderMatch) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMPolicyRateLimitMetadataMatch) DeepCopyInto(out *LLMPolicyRateLimitMetadataMatch) { + *out = *in + if in.Paths != nil { + in, out := &in.Paths, &out.Paths + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.DefaultValue != nil { + in, out := &in.DefaultValue, &out.DefaultValue + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMPolicyRateLimitMetadataMatch. +func (in *LLMPolicyRateLimitMetadataMatch) DeepCopy() *LLMPolicyRateLimitMetadataMatch { + if in == nil { + return nil + } + out := new(LLMPolicyRateLimitMetadataMatch) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMPolicyRateLimitModelNameMatch) DeepCopyInto(out *LLMPolicyRateLimitModelNameMatch) { + *out = *in + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMPolicyRateLimitModelNameMatch. +func (in *LLMPolicyRateLimitModelNameMatch) DeepCopy() *LLMPolicyRateLimitModelNameMatch { + if in == nil { + return nil + } + out := new(LLMPolicyRateLimitModelNameMatch) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMPolicyRateLimitValue) DeepCopyInto(out *LLMPolicyRateLimitValue) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMPolicyRateLimitValue. +func (in *LLMPolicyRateLimitValue) DeepCopy() *LLMPolicyRateLimitValue { + if in == nil { + return nil + } + out := new(LLMPolicyRateLimitValue) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LLMRoute) DeepCopyInto(out *LLMRoute) { *out = *in @@ -198,3 +358,86 @@ func (in *LLMRouteSpec) DeepCopy() *LLMRouteSpec { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMTrafficPolicyRateLimit) DeepCopyInto(out *LLMTrafficPolicyRateLimit) { + *out = *in + if in.Rules != nil { + in, out := &in.Rules, &out.Rules + *out = make([]LLMTrafficPolicyRateLimitRule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMTrafficPolicyRateLimit. +func (in *LLMTrafficPolicyRateLimit) DeepCopy() *LLMTrafficPolicyRateLimit { + if in == nil { + return nil + } + out := new(LLMTrafficPolicyRateLimit) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMTrafficPolicyRateLimitRule) DeepCopyInto(out *LLMTrafficPolicyRateLimitRule) { + *out = *in + if in.Headers != nil { + in, out := &in.Headers, &out.Headers + *out = make([]LLMPolicyRateLimitHeaderMatch, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = make([]LLMPolicyRateLimitMetadataMatch, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Limits != nil { + in, out := &in.Limits, &out.Limits + *out = make([]LLMPolicyRateLimitValue, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMTrafficPolicyRateLimitRule. +func (in *LLMTrafficPolicyRateLimitRule) DeepCopy() *LLMTrafficPolicyRateLimitRule { + if in == nil { + return nil + } + out := new(LLMTrafficPolicyRateLimitRule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetSelector) DeepCopyInto(out *TargetSelector) { + *out = *in + if in.Group != nil { + in, out := &in.Group, &out.Group + *out = new(v1.Group) + **out = **in + } + if in.MatchLabels != nil { + in, out := &in.MatchLabels, &out.MatchLabels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetSelector. +func (in *TargetSelector) DeepCopy() *TargetSelector { + if in == nil { + return nil + } + out := new(TargetSelector) + in.DeepCopyInto(out) + return out +} diff --git a/manifests/charts/ai-gateway-helm/crds/aigateway.envoyproxy.io_llmbackendtrafficpolicies.yaml b/manifests/charts/ai-gateway-helm/crds/aigateway.envoyproxy.io_llmbackendtrafficpolicies.yaml new file mode 100644 index 00000000..97727c1f --- /dev/null +++ b/manifests/charts/ai-gateway-helm/crds/aigateway.envoyproxy.io_llmbackendtrafficpolicies.yaml @@ -0,0 +1,183 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.2 + name: llmbackendtrafficpolicies.aigateway.envoyproxy.io +spec: + group: aigateway.envoyproxy.io + names: + kind: LLMBackendTrafficPolicy + listKind: LLMBackendTrafficPolicyList + plural: llmbackendtrafficpolicies + singular: llmbackendtrafficpolicy + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: LLMBackendTrafficPolicy controls the flow of traffic to the backend. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the details of the LLMBackend traffic policy. + properties: + backendRef: + description: |- + BackendRefs lists the LLMBackends that this traffic policy will apply + The namespace is "local", i.e. the same namespace as the LLMRoute. + properties: + name: + description: Name is the name of the LLMBackend in the same namespace + as the LLMRoute. + type: string + required: + - name + type: object + rateLimit: + description: RateLimit defines the rate limit policy. + properties: + rules: + description: Rules defines the rate limit rules. + items: + description: LLMTrafficPolicyRateLimitRule defines the details + of the rate limit policy. + properties: + headers: + description: |- + Headers is a list of request headers to match. Multiple header values are ANDed together, + meaning, a request MUST match all the specified headers. + At least one of headers or sourceCIDR condition must be specified. + items: + description: LLMPolicyRateLimitHeaderMatch defines the + match attributes within the HTTP Headers of the request. + properties: + name: + description: Name of the HTTP header. + maxLength: 256 + minLength: 1 + type: string + type: + description: Type specifies how to match against the + value of the header. + enum: + - Exact + - RegularExpression + - Distinct + type: string + value: + description: |- + Value within the HTTP header. Due to the + case-insensitivity of header names, "foo" and "Foo" are considered equivalent. + Do not set this field when Type="Distinct", implying matching on any/all unique + values within the header. + maxLength: 1024 + type: string + required: + - name + - type + type: object + type: array + limits: + description: |- + Limits holds the rate limit values. + This limit is applied for traffic flows when the selectors + compute to True, causing the request to be counted towards the limit. + The limit is enforced and the request is ratelimited, i.e. a response with + 429 HTTP status code is sent back to the client when + the selected requests have reached the limit. + items: + description: LLMPolicyRateLimitValue defines the limits + for rate limiting. + properties: + quantity: + description: Quantity specifies the number of requests + or tokens allowed in the given interval. + type: integer + type: + default: Request + description: Type specifies the type of rate limit. + enum: + - Request + - Token + type: string + unit: + default: Minute + description: Unit specifies the interval for the rate + limit. + enum: + - Second + - Minute + - Hour + - Day + type: string + required: + - quantity + - type + - unit + type: object + minItems: 1 + type: array + metadata: + description: Metadata is a list of metadata to match. Multiple + metadata values are ANDed together, + items: + description: |- + LLMPolicyRateLimitMetadataMatch defines the match attributes within the metadata from dynamic or route entry. + The match will be ignored if the metadata is not present. + properties: + defaultValue: + description: |- + DefaultValue specifies an optional value to use if “metadata“ is empty. + Default value is "unknown". + type: string + name: + description: Name specifies the key of the metadata + to match. + type: string + paths: + description: Paths specifies the value of the metadata + to match. + items: + type: string + maxItems: 32 + type: array + type: + default: Dynamic + description: Type specifies the type of metadata to + match. + enum: + - Dynamic + - RouteEntry + type: string + required: + - name + - type + type: object + type: array + required: + - limits + type: object + type: array + type: object + type: object + type: object + served: true + storage: true