From 3fb679016423e80b87cf3e540d296471223460e6 Mon Sep 17 00:00:00 2001 From: Cici Huang Date: Tue, 5 Dec 2023 23:26:13 +0000 Subject: [PATCH] Update env version, Add cost for previous func, add tests, etc. --- .../schema/cel/celcoststability_test.go | 39 +++++++++++++++++++ .../apiserver/schema/cel/validation_test.go | 17 ++++++++ .../apiserver/pkg/cel/environment/base.go | 2 +- .../k8s.io/apiserver/pkg/cel/library/cost.go | 15 +++++++ 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/celcoststability_test.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/celcoststability_test.go index 4dcb0d44f98..b451756b3ff 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/celcoststability_test.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/celcoststability_test.go @@ -1130,6 +1130,26 @@ func TestCelCostStability(t *testing.T) { "optional.ofNonZeroValue(1).hasValue()": 2, }, }, + {name: "quantity", + obj: objs("20", "200M"), + schema: schemas(stringType, stringType), + expectCost: map[string]int64{ + `isQuantity(self.val1)`: 3, + `isQuantity(self.val2)`: 3, + `isQuantity("200M")`: 1, + `isQuantity("20Mi")`: 1, + `quantity("200M") == quantity("0.2G") && quantity("0.2G") == quantity("200M")`: 6, + `quantity("2M") == quantity("0.002G") && quantity("2000k") == quantity("2M") && quantity("0.002G") == quantity("2000k")`: 9, + `quantity(self.val1).isLessThan(quantity(self.val2))`: 7, + `quantity("50M").isLessThan(quantity("100M"))`: 3, + `quantity("50Mi").isGreaterThan(quantity("50M"))`: 3, + `quantity("200M").compareTo(quantity("0.2G")) == 0`: 4, + `quantity("50k").add(quantity("20")) == quantity("50.02k")`: 5, + `quantity("50k").sub(20) == quantity("49980")`: 4, + `quantity("50").isInteger()`: 2, + `quantity(self.val1).isInteger()`: 4, + }, + }, } for _, tt := range cases { @@ -1939,6 +1959,25 @@ func TestCelEstimatedCostStability(t *testing.T) { "optional.ofNonZeroValue(1).hasValue()": 2, }, }, + {name: "quantity", + schema: schemas(stringType, stringType), + expectCost: map[string]uint64{ + `isQuantity(self.val1)`: 314575, + `isQuantity(self.val2)`: 314575, + `isQuantity("200M")`: 1, + `isQuantity("20Mi")`: 1, + `quantity("200M") == quantity("0.2G") && quantity("0.2G") == quantity("200M")`: uint64(3689348814741910532), + `quantity("2M") == quantity("0.002G") && quantity("2000k") == quantity("2M") && quantity("0.002G") == quantity("2000k")`: uint64(5534023222112865798), + `quantity(self.val1).isLessThan(quantity(self.val2))`: 629151, + `quantity("50M").isLessThan(quantity("100M"))`: 3, + `quantity("50Mi").isGreaterThan(quantity("50M"))`: 3, + `quantity("200M").compareTo(quantity("0.2G")) == 0`: 4, + `quantity("50k").add(quantity("20")) == quantity("50.02k")`: uint64(1844674407370955268), + `quantity("50k").sub(20) == quantity("49980")`: uint64(1844674407370955267), + `quantity("50").isInteger()`: 2, + `quantity(self.val1).isInteger()`: 314576, + }, + }, } for _, tt := range cases { diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/validation_test.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/validation_test.go index 63119ebaa22..3e6291dd8e9 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/validation_test.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/validation_test.go @@ -1952,6 +1952,23 @@ func TestValidationExpressions(t *testing.T) { "self.absentObj.?absentStr == optional.none()": "no such key: absentObj", // missing ?. operator on first deref is an error }, }, + {name: "quantity", + obj: objs("20", "200M"), + schema: schemas(stringType, stringType), + valid: []string{ + "isQuantity(self.val1)", + "isQuantity(self.val2)", + `isQuantity("20Mi")`, + `quantity(self.val2) == quantity("0.2G") && quantity("0.2G") == quantity("200M")`, + `quantity("2M") == quantity("0.002G") && quantity("2000k") == quantity("2M") && quantity("0.002G") == quantity("2000k")`, + `quantity(self.val1).isLessThan(quantity("100M"))`, + `quantity(self.val2).isGreaterThan(quantity("50M"))`, + `quantity(self.val2).compareTo(quantity("0.2G")) == 0`, + `quantity("50k").add(quantity(self.val1)) == quantity("50.02k")`, + `quantity("50k").sub(quantity(self.val1)) == quantity("49980")`, + `quantity(self.val1).isInteger()`, + }, + }, } for i := range tests { diff --git a/staging/src/k8s.io/apiserver/pkg/cel/environment/base.go b/staging/src/k8s.io/apiserver/pkg/cel/environment/base.go index 4dce93a7925..c108bdd644f 100644 --- a/staging/src/k8s.io/apiserver/pkg/cel/environment/base.go +++ b/staging/src/k8s.io/apiserver/pkg/cel/environment/base.go @@ -43,7 +43,7 @@ import ( // desirable because it means that CEL expressions are portable across a wider range // of Kubernetes versions. func DefaultCompatibilityVersion() *version.Version { - return version.MajorMinor(1, 28) + return version.MajorMinor(1, 29) } var baseOpts = []VersionedOptions{ diff --git a/staging/src/k8s.io/apiserver/pkg/cel/library/cost.go b/staging/src/k8s.io/apiserver/pkg/cel/library/cost.go index a723937f19f..e3bde017bea 100644 --- a/staging/src/k8s.io/apiserver/pkg/cel/library/cost.go +++ b/staging/src/k8s.io/apiserver/pkg/cel/library/cost.go @@ -147,6 +147,14 @@ func (l *CostEstimator) CallCost(function, overloadId string, args []ref.Val, re return &cost } + case "quantity", "isQuantity": + if len(args) >= 1 { + cost := uint64(math.Ceil(float64(actualSize(args[0])) * common.StringTraversalCostFactor)) + return &cost + } + case "sign", "asInteger", "isInteger", "asApproximateFloat", "isGreaterThan", "isLessThan", "compareTo", "add", "sub": + cost := uint64(1) + return &cost } return nil } @@ -360,6 +368,13 @@ func (l *CostEstimator) EstimateCallCost(function, overloadId string, target *ch return &checker.CallEstimate{CostEstimate: ipCompCost} } + case "quantity", "isQuantity": + if target != nil { + sz := l.sizeEstimate(args[0]) + return &checker.CallEstimate{CostEstimate: sz.MultiplyByCostFactor(common.StringTraversalCostFactor)} + } + case "sign", "asInteger", "isInteger", "asApproximateFloat", "isGreaterThan", "isLessThan", "compareTo", "add", "sub": + return &checker.CallEstimate{CostEstimate: checker.CostEstimate{Min: 1, Max: 1}} } return nil }