Skip to content

Commit

Permalink
add cel test and address comments
Browse files Browse the repository at this point in the history
Signed-off-by: yweng14 <[email protected]>
  • Loading branch information
wengyao04 committed Dec 6, 2024
1 parent f00f31b commit 3deaf80
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 212 deletions.
104 changes: 19 additions & 85 deletions api/v1alpha1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,32 +165,10 @@ type LLMTrafficPolicyRateLimitRule struct {
// 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.
Expand Down Expand Up @@ -219,62 +197,32 @@ type LLMPolicyRateLimitStringMatchType string

// HeaderMatchType constants.
const (
// HeaderMatchExact matches the exact value of the Value field against the value of
// LLMPolicyRateLimitStringMatchHeaderMatchExact matches the exact value of the Value field against the value of
// the specified HTTP Header.
HeaderMatchExact LLMPolicyRateLimitStringMatchType = "Exact"
LLMPolicyRateLimitStringMatchHeaderMatchExact 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
// LLMPolicyRateLimitStringMatchHeaderMatchDistinct 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"
LLMPolicyRateLimitStringMatchHeaderMatchDistinct LLMPolicyRateLimitStringMatchType = "Distinct"
)

// LLMPolicyRateLimitValue defines the limits for rate limiting.
type LLMPolicyRateLimitValue struct {
// Type specifies the type of rate limit.
//
// +kubebuilder:default=Request
Type LLMPolicyRateLimitType `json:"type"`
// +kubebuilder:default=Token
Type LLMPolicyRateLimitType `json:"type,omitempty"`
// 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"`
Unit LLMPolicyRateLimitUnit `json:"unit,omitempty"`
}

// LLMPolicyRateLimitType specifies the type of rate limit.
Expand All @@ -284,10 +232,10 @@ type LLMPolicyRateLimitValue struct {
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"
// LLMPolicyRateLimitTypeRequest specifies the rate limit to be based on the number of requests.
LLMPolicyRateLimitTypeRequest LLMPolicyRateLimitType = "Request"
// LLMPolicyRateLimitTypeToken specifies the rate limit to be based on the number of tokens.
LLMPolicyRateLimitTypeToken LLMPolicyRateLimitType = "Token"
)

// LLMPolicyRateLimitUnit specifies the intervals for setting rate limits.
Expand All @@ -298,29 +246,15 @@ type LLMPolicyRateLimitUnit string

// RateLimitUnit constants.
const (
// RateLimitUnitSecond specifies the rate limit interval to be 1 second.
RateLimitUnitSecond LLMPolicyRateLimitUnit = "Second"
// LLMPolicyRateLimitUnitSecond specifies the rate limit interval to be 1 second.
LLMPolicyRateLimitUnitSecond LLMPolicyRateLimitUnit = "Second"

// RateLimitUnitMinute specifies the rate limit interval to be 1 minute.
RateLimitUnitMinute LLMPolicyRateLimitUnit = "Minute"
// LLMPolicyRateLimitUnitMinute specifies the rate limit interval to be 1 minute.
LLMPolicyRateLimitUnitMinute LLMPolicyRateLimitUnit = "Minute"

// RateLimitUnitHour specifies the rate limit interval to be 1 hour.
RateLimitUnitHour LLMPolicyRateLimitUnit = "Hour"
// LLMPolicyRateLimitUnitHour specifies the rate limit interval to be 1 hour.
LLMPolicyRateLimitUnitHour LLMPolicyRateLimitUnit = "Hour"

// RateLimitUnitDay specifies the rate limit interval to be 1 day.
RateLimitUnitDay LLMPolicyRateLimitUnit = "Day"
// LLMPolicyRateLimitUnitDay specifies the rate limit interval to be 1 day.
LLMPolicyRateLimitUnitDay 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"`
}
1 change: 1 addition & 0 deletions api/v1alpha1/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
func init() {
SchemeBuilder.Register(&LLMRoute{}, &LLMRouteList{})
SchemeBuilder.Register(&LLMBackend{}, &LLMBackendList{})
SchemeBuilder.Register(&LLMBackendTrafficPolicy{}, &LLMBackendTrafficPolicyList{})
}

const GroupName = "aigateway.envoyproxy.io"
Expand Down
80 changes: 0 additions & 80 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,6 @@ spec:
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.
Expand All @@ -112,7 +105,7 @@ spec:
or tokens allowed in the given interval.
type: integer
type:
default: Request
default: Token
description: Type specifies the type of rate limit.
enum:
- Request
Expand All @@ -130,48 +123,9 @@ spec:
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
Expand Down
37 changes: 37 additions & 0 deletions tests/cel-validation/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func runTest(m *testing.M) int {
for _, crd := range []string{
"aigateway.envoyproxy.io_llmroutes.yaml",
"aigateway.envoyproxy.io_llmbackends.yaml",
"aigateway.envoyproxy.io_llmbackendtrafficpolicies.yaml",
} {
crds = append(crds, filepath.Join(base, crd))
}
Expand Down Expand Up @@ -133,3 +134,39 @@ func TestLLMBackends(t *testing.T) {
})
}
}

func TestLLMBackendTrafficPolicy(t *testing.T) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(30*time.Second))
defer cancel()

for _, tc := range []struct {
name string
expErr string
}{
{name: "basic.yaml"},
{
name: "unknown_ratelimit_type.yaml",
expErr: "spec.rateLimit.rules[0].limits[0].type: Unsupported value: \"Foo\": supported values: \"Request\", \"Token\"",
},
{
name: "unknown_ratelimit_unit.yaml",
expErr: "spec.rateLimit.rules[0].limits[0].unit: Unsupported value: \"Foo\": supported values: \"Second\", \"Minute\", \"Hour\", \"Day\"",
},
} {
t.Run(tc.name, func(t *testing.T) {
data, err := tests.ReadFile(path.Join("testdata/llmbackendtrafficpolicies", tc.name))
require.NoError(t, err)

llmBackendTrafficPolicy := &aigv1a1.LLMBackendTrafficPolicy{}
err = yaml.UnmarshalStrict(data, llmBackendTrafficPolicy)
require.NoError(t, err)

if tc.expErr != "" {
require.ErrorContains(t, c.Create(ctx, llmBackendTrafficPolicy), tc.expErr)
} else {
require.NoError(t, c.Create(ctx, llmBackendTrafficPolicy))
require.NoError(t, c.Delete(ctx, llmBackendTrafficPolicy))
}
})
}
}
Loading

0 comments on commit 3deaf80

Please sign in to comment.