Skip to content

Commit e085f38

Browse files
committed
Move CEL semver library into common libs, fix cost tests to use registered types
1 parent 0a2dfba commit e085f38

File tree

13 files changed

+65
-54
lines changed

13 files changed

+65
-54
lines changed

staging/src/k8s.io/apiserver/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ go 1.22.0
66

77
require (
88
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a
9+
github.com/blang/semver/v4 v4.0.0
910
github.com/coreos/go-oidc v2.2.1+incompatible
1011
github.com/coreos/go-systemd/v22 v22.5.0
1112
github.com/emicklei/go-restful/v3 v3.11.0
@@ -63,7 +64,6 @@ require (
6364
github.com/NYTimes/gziphandler v1.1.1 // indirect
6465
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
6566
github.com/beorn7/perks v1.0.1 // indirect
66-
github.com/blang/semver/v4 v4.0.0 // indirect
6767
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
6868
github.com/cespare/xxhash/v2 v2.3.0 // indirect
6969
github.com/coreos/go-semver v0.3.1 // indirect

staging/src/k8s.io/apiserver/pkg/cel/format.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ type Format struct {
4141
MaxRegexSize int
4242
}
4343

44-
func (d *Format) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
44+
func (d Format) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
4545
return nil, fmt.Errorf("type conversion error from 'Format' to '%v'", typeDesc)
4646
}
4747

48-
func (d *Format) ConvertToType(typeVal ref.Type) ref.Val {
48+
func (d Format) ConvertToType(typeVal ref.Type) ref.Val {
4949
switch typeVal {
5050
case FormatType:
5151
return d
@@ -56,18 +56,18 @@ func (d *Format) ConvertToType(typeVal ref.Type) ref.Val {
5656
}
5757
}
5858

59-
func (d *Format) Equal(other ref.Val) ref.Val {
60-
otherDur, ok := other.(*Format)
59+
func (d Format) Equal(other ref.Val) ref.Val {
60+
otherDur, ok := other.(Format)
6161
if !ok {
6262
return types.MaybeNoSuchOverloadErr(other)
6363
}
6464
return types.Bool(d.Name == otherDur.Name)
6565
}
6666

67-
func (d *Format) Type() ref.Type {
67+
func (d Format) Type() ref.Type {
6868
return FormatType
6969
}
7070

71-
func (d *Format) Value() interface{} {
71+
func (d Format) Value() interface{} {
7272
return d
7373
}

staging/src/k8s.io/apiserver/pkg/cel/library/cidr.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ var cidrsLib = &cidrs{}
109109
type cidrs struct{}
110110

111111
func (*cidrs) LibraryName() string {
112-
return "net.cidr"
112+
return "kubernetes.net.cidr"
113113
}
114114

115115
func (*cidrs) declarations() map[string][]cel.FunctionOpt {

staging/src/k8s.io/apiserver/pkg/cel/library/cost.go

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"github.com/google/cel-go/common/types/ref"
2626
"github.com/google/cel-go/common/types/traits"
2727
"math"
28-
"strings"
2928

3029
"k8s.io/apiserver/pkg/cel"
3130
)
@@ -201,7 +200,7 @@ func (l *CostEstimator) CallCost(function, overloadId string, args []ref.Val, re
201200
}
202201
case "validate":
203202
if len(args) >= 2 {
204-
format, isFormat := args[0].Value().(*cel.Format)
203+
format, isFormat := args[0].Value().(cel.Format)
205204
if isFormat {
206205
strSize := actualSize(args[1])
207206

@@ -243,13 +242,14 @@ func (l *CostEstimator) CallCost(function, overloadId string, args []ref.Val, re
243242
case *cel.Quantity, cel.Quantity,
244243
*cel.IP, cel.IP,
245244
*cel.CIDR, cel.CIDR,
246-
*cel.Format, // Formats have a small max size. Format takes pointer receiver.
245+
*cel.Format, cel.Format, // Formats have a small max size. Format takes pointer receiver.
247246
*cel.URL, cel.URL, // TODO: Computing the actual cost is expensive, and changing this would be a breaking change
247+
*cel.Semver, cel.Semver,
248248
*authorizerVal, authorizerVal, *pathCheckVal, pathCheckVal, *groupCheckVal, groupCheckVal,
249249
*resourceCheckVal, resourceCheckVal, *decisionVal, decisionVal:
250250
return &unitCost
251251
default:
252-
if panicOnUnknown && isKubernetesType(lhs.Type()) {
252+
if panicOnUnknown && lhs.Type() != nil && isRegisteredType(lhs.Type().TypeName()) {
253253
panic(fmt.Errorf("CallCost: unhandled equality for Kubernetes type %T", lhs))
254254
}
255255
}
@@ -509,7 +509,7 @@ func (l *CostEstimator) EstimateCallCost(function, overloadId string, target *ch
509509
if t.Kind() == types.StructKind {
510510
switch t {
511511
case cel.QuantityType, AuthorizerType, PathCheckType, // O(1) cost equality checks
512-
GroupCheckType, ResourceCheckType, DecisionType:
512+
GroupCheckType, ResourceCheckType, DecisionType, cel.SemverType:
513513
return &checker.CallEstimate{CostEstimate: checker.CostEstimate{Min: 1, Max: 1}}
514514
case cel.FormatType:
515515
return &checker.CallEstimate{CostEstimate: checker.CostEstimate{Min: 1, Max: cel.MaxFormatSize}.MultiplyByCostFactor(common.StringTraversalCostFactor)}
@@ -523,7 +523,7 @@ func (l *CostEstimator) EstimateCallCost(function, overloadId string, target *ch
523523
return &checker.CallEstimate{CostEstimate: checker.CostEstimate{Min: 1, Max: size.Max}.MultiplyByCostFactor(common.StringTraversalCostFactor)}
524524
}
525525
}
526-
if panicOnUnknown && isKubernetesType(t) {
526+
if panicOnUnknown && isRegisteredType(t.TypeName()) {
527527
panic(fmt.Errorf("EstimateCallCost: unhandled equality for Kubernetes type %v", t))
528528
}
529529
}
@@ -632,17 +632,3 @@ func traversalCost(v ref.Val) uint64 {
632632
return 1
633633
}
634634
}
635-
636-
// isKubernetesType returns ture if a type is type defined by Kubernetes,
637-
// as identified by opaque or struct types with a "kubernetes." prefix.
638-
func isKubernetesType(t ref.Type) bool {
639-
if tt, ok := t.(*types.Type); ok {
640-
switch tt.Kind() {
641-
case types.OpaqueKind, types.StructKind:
642-
return strings.HasPrefix(tt.TypeName(), "kubernetes.")
643-
default:
644-
return false
645-
}
646-
}
647-
return false
648-
}

staging/src/k8s.io/apiserver/pkg/cel/library/cost_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1262,7 +1262,8 @@ func TestTypeEquality(t *testing.T) {
12621262
"kubernetes.Quantity": apiservercel.Quantity{},
12631263
"net.IP": apiservercel.IP{},
12641264
"net.CIDR": apiservercel.CIDR{},
1265-
"kubernetes.NamedFormat": &apiservercel.Format{},
1265+
"kubernetes.NamedFormat": apiservercel.Format{},
1266+
"kubernetes.Semver": apiservercel.Semver{},
12661267
}
12671268

12681269
originalPanicOnUnknown := panicOnUnknown

staging/src/k8s.io/apiserver/pkg/cel/library/format.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ func (*format) ProgramOptions() []cel.ProgramOption {
133133
return []cel.ProgramOption{}
134134
}
135135

136-
var ConstantFormats map[string]*apiservercel.Format = map[string]*apiservercel.Format{
136+
var ConstantFormats = map[string]apiservercel.Format{
137137
"dns1123Label": {
138138
Name: "DNS1123Label",
139139
ValidateFunc: func(s string) []string { return apimachineryvalidation.NameIsDNSLabel(s, false) },
@@ -261,7 +261,7 @@ var formatLibraryDecls = map[string][]cel.FunctionOpt{
261261
}
262262

263263
func formatValidate(arg1, arg2 ref.Val) ref.Val {
264-
f, ok := arg1.Value().(*apiservercel.Format)
264+
f, ok := arg1.Value().(apiservercel.Format)
265265
if !ok {
266266
return types.MaybeNoSuchOverloadErr(arg1)
267267
}

staging/src/k8s.io/apiserver/pkg/cel/library/ip.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ var ipLib = &ip{}
132132
type ip struct{}
133133

134134
func (*ip) LibraryName() string {
135-
return "net.ip"
135+
return "kubernetes.net.ip"
136136
}
137137

138138
func (*ip) declarations() map[string][]cel.FunctionOpt {

staging/src/k8s.io/apiserver/pkg/cel/library/libraries.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2023 The Kubernetes Authors.
2+
Copyright 2024 The Kubernetes Authors.
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -16,7 +16,9 @@ limitations under the License.
1616

1717
package library
1818

19-
import "github.com/google/cel-go/cel"
19+
import (
20+
"github.com/google/cel-go/cel"
21+
)
2022

2123
// Library represents a CEL library used by kubernetes.
2224
type Library interface {
@@ -42,5 +44,17 @@ func KnownLibraries() []Library {
4244
ipLib,
4345
cidrsLib,
4446
formatLib,
47+
semverLib,
4548
}
4649
}
50+
51+
func isRegisteredType(typeName string) bool {
52+
for _, lib := range KnownLibraries() {
53+
for _, rt := range lib.Types() {
54+
if rt.TypeName() == typeName {
55+
return true
56+
}
57+
}
58+
}
59+
return false
60+
}

staging/src/k8s.io/apiserver/pkg/cel/library/library_compatibility_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func TestLibraryCompatibility(t *testing.T) {
4949
// Kubernetes <1.30>:
5050
"ip", "family", "isUnspecified", "isLoopback", "isLinkLocalMulticast", "isLinkLocalUnicast", "isGlobalUnicast", "ip.isCanonical", "isIP", "cidr", "containsIP", "containsCIDR", "masked", "prefixLength", "isCIDR", "string",
5151
// Kubernetes <1.31>:
52-
"fieldSelector", "labelSelector", "validate", "format.named",
52+
"fieldSelector", "labelSelector", "validate", "format.named", "isSemver", "major", "minor", "patch", "semver",
5353
// Kubernetes <1.??>:
5454
)
5555

@@ -101,5 +101,4 @@ func TestTypeRegistration(t *testing.T) {
101101
t.Errorf("Expected types to be registered with the %s library Type() functions, but they were not: %v", lib.LibraryName(), unregistered)
102102
}
103103
}
104-
105104
}

staging/src/k8s.io/dynamic-resource-allocation/cel/semver_test.go renamed to staging/src/k8s.io/apiserver/pkg/cel/library/semver_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package cel_test
17+
package library_test
1818

1919
import (
2020
"regexp"
@@ -27,7 +27,8 @@ import (
2727
"github.com/stretchr/testify/require"
2828

2929
"k8s.io/apimachinery/pkg/util/sets"
30-
library "k8s.io/dynamic-resource-allocation/cel"
30+
apiservercel "k8s.io/apiserver/pkg/cel"
31+
library "k8s.io/apiserver/pkg/cel/library"
3132
)
3233

3334
func testSemver(t *testing.T, expr string, expectResult ref.Val, expectRuntimeErrPattern string, expectCompileErrs []string) {
@@ -117,7 +118,7 @@ func TestSemver(t *testing.T) {
117118
{
118119
name: "parse",
119120
expr: `semver("1.2.3")`,
120-
expectValue: library.Semver{Version: semver.MustParse("1.2.3")},
121+
expectValue: apiservercel.Semver{Version: semver.MustParse("1.2.3")},
121122
},
122123
{
123124
name: "parseInvalidVersion",

0 commit comments

Comments
 (0)