mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-17 15:50:10 +00:00
Move CEL semver library into common libs, fix cost tests to use registered types
This commit is contained in:
parent
0a2dfba067
commit
e085f3818a
@ -6,6 +6,7 @@ go 1.22.0
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a
|
||||||
|
github.com/blang/semver/v4 v4.0.0
|
||||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0
|
github.com/coreos/go-systemd/v22 v22.5.0
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0
|
github.com/emicklei/go-restful/v3 v3.11.0
|
||||||
@ -63,7 +64,6 @@ require (
|
|||||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/coreos/go-semver v0.3.1 // indirect
|
github.com/coreos/go-semver v0.3.1 // indirect
|
||||||
|
@ -41,11 +41,11 @@ type Format struct {
|
|||||||
MaxRegexSize int
|
MaxRegexSize int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Format) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
func (d Format) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||||
return nil, fmt.Errorf("type conversion error from 'Format' to '%v'", typeDesc)
|
return nil, fmt.Errorf("type conversion error from 'Format' to '%v'", typeDesc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Format) ConvertToType(typeVal ref.Type) ref.Val {
|
func (d Format) ConvertToType(typeVal ref.Type) ref.Val {
|
||||||
switch typeVal {
|
switch typeVal {
|
||||||
case FormatType:
|
case FormatType:
|
||||||
return d
|
return d
|
||||||
@ -56,18 +56,18 @@ func (d *Format) ConvertToType(typeVal ref.Type) ref.Val {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Format) Equal(other ref.Val) ref.Val {
|
func (d Format) Equal(other ref.Val) ref.Val {
|
||||||
otherDur, ok := other.(*Format)
|
otherDur, ok := other.(Format)
|
||||||
if !ok {
|
if !ok {
|
||||||
return types.MaybeNoSuchOverloadErr(other)
|
return types.MaybeNoSuchOverloadErr(other)
|
||||||
}
|
}
|
||||||
return types.Bool(d.Name == otherDur.Name)
|
return types.Bool(d.Name == otherDur.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Format) Type() ref.Type {
|
func (d Format) Type() ref.Type {
|
||||||
return FormatType
|
return FormatType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Format) Value() interface{} {
|
func (d Format) Value() interface{} {
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ var cidrsLib = &cidrs{}
|
|||||||
type cidrs struct{}
|
type cidrs struct{}
|
||||||
|
|
||||||
func (*cidrs) LibraryName() string {
|
func (*cidrs) LibraryName() string {
|
||||||
return "net.cidr"
|
return "kubernetes.net.cidr"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*cidrs) declarations() map[string][]cel.FunctionOpt {
|
func (*cidrs) declarations() map[string][]cel.FunctionOpt {
|
||||||
|
@ -25,7 +25,6 @@ import (
|
|||||||
"github.com/google/cel-go/common/types/ref"
|
"github.com/google/cel-go/common/types/ref"
|
||||||
"github.com/google/cel-go/common/types/traits"
|
"github.com/google/cel-go/common/types/traits"
|
||||||
"math"
|
"math"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"k8s.io/apiserver/pkg/cel"
|
"k8s.io/apiserver/pkg/cel"
|
||||||
)
|
)
|
||||||
@ -201,7 +200,7 @@ func (l *CostEstimator) CallCost(function, overloadId string, args []ref.Val, re
|
|||||||
}
|
}
|
||||||
case "validate":
|
case "validate":
|
||||||
if len(args) >= 2 {
|
if len(args) >= 2 {
|
||||||
format, isFormat := args[0].Value().(*cel.Format)
|
format, isFormat := args[0].Value().(cel.Format)
|
||||||
if isFormat {
|
if isFormat {
|
||||||
strSize := actualSize(args[1])
|
strSize := actualSize(args[1])
|
||||||
|
|
||||||
@ -243,13 +242,14 @@ func (l *CostEstimator) CallCost(function, overloadId string, args []ref.Val, re
|
|||||||
case *cel.Quantity, cel.Quantity,
|
case *cel.Quantity, cel.Quantity,
|
||||||
*cel.IP, cel.IP,
|
*cel.IP, cel.IP,
|
||||||
*cel.CIDR, cel.CIDR,
|
*cel.CIDR, cel.CIDR,
|
||||||
*cel.Format, // Formats have a small max size. Format takes pointer receiver.
|
*cel.Format, cel.Format, // Formats have a small max size. Format takes pointer receiver.
|
||||||
*cel.URL, cel.URL, // TODO: Computing the actual cost is expensive, and changing this would be a breaking change
|
*cel.URL, cel.URL, // TODO: Computing the actual cost is expensive, and changing this would be a breaking change
|
||||||
|
*cel.Semver, cel.Semver,
|
||||||
*authorizerVal, authorizerVal, *pathCheckVal, pathCheckVal, *groupCheckVal, groupCheckVal,
|
*authorizerVal, authorizerVal, *pathCheckVal, pathCheckVal, *groupCheckVal, groupCheckVal,
|
||||||
*resourceCheckVal, resourceCheckVal, *decisionVal, decisionVal:
|
*resourceCheckVal, resourceCheckVal, *decisionVal, decisionVal:
|
||||||
return &unitCost
|
return &unitCost
|
||||||
default:
|
default:
|
||||||
if panicOnUnknown && isKubernetesType(lhs.Type()) {
|
if panicOnUnknown && lhs.Type() != nil && isRegisteredType(lhs.Type().TypeName()) {
|
||||||
panic(fmt.Errorf("CallCost: unhandled equality for Kubernetes type %T", lhs))
|
panic(fmt.Errorf("CallCost: unhandled equality for Kubernetes type %T", lhs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -509,7 +509,7 @@ func (l *CostEstimator) EstimateCallCost(function, overloadId string, target *ch
|
|||||||
if t.Kind() == types.StructKind {
|
if t.Kind() == types.StructKind {
|
||||||
switch t {
|
switch t {
|
||||||
case cel.QuantityType, AuthorizerType, PathCheckType, // O(1) cost equality checks
|
case cel.QuantityType, AuthorizerType, PathCheckType, // O(1) cost equality checks
|
||||||
GroupCheckType, ResourceCheckType, DecisionType:
|
GroupCheckType, ResourceCheckType, DecisionType, cel.SemverType:
|
||||||
return &checker.CallEstimate{CostEstimate: checker.CostEstimate{Min: 1, Max: 1}}
|
return &checker.CallEstimate{CostEstimate: checker.CostEstimate{Min: 1, Max: 1}}
|
||||||
case cel.FormatType:
|
case cel.FormatType:
|
||||||
return &checker.CallEstimate{CostEstimate: checker.CostEstimate{Min: 1, Max: cel.MaxFormatSize}.MultiplyByCostFactor(common.StringTraversalCostFactor)}
|
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
|
|||||||
return &checker.CallEstimate{CostEstimate: checker.CostEstimate{Min: 1, Max: size.Max}.MultiplyByCostFactor(common.StringTraversalCostFactor)}
|
return &checker.CallEstimate{CostEstimate: checker.CostEstimate{Min: 1, Max: size.Max}.MultiplyByCostFactor(common.StringTraversalCostFactor)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if panicOnUnknown && isKubernetesType(t) {
|
if panicOnUnknown && isRegisteredType(t.TypeName()) {
|
||||||
panic(fmt.Errorf("EstimateCallCost: unhandled equality for Kubernetes type %v", t))
|
panic(fmt.Errorf("EstimateCallCost: unhandled equality for Kubernetes type %v", t))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -632,17 +632,3 @@ func traversalCost(v ref.Val) uint64 {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// isKubernetesType returns ture if a type is type defined by Kubernetes,
|
|
||||||
// as identified by opaque or struct types with a "kubernetes." prefix.
|
|
||||||
func isKubernetesType(t ref.Type) bool {
|
|
||||||
if tt, ok := t.(*types.Type); ok {
|
|
||||||
switch tt.Kind() {
|
|
||||||
case types.OpaqueKind, types.StructKind:
|
|
||||||
return strings.HasPrefix(tt.TypeName(), "kubernetes.")
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
@ -1262,7 +1262,8 @@ func TestTypeEquality(t *testing.T) {
|
|||||||
"kubernetes.Quantity": apiservercel.Quantity{},
|
"kubernetes.Quantity": apiservercel.Quantity{},
|
||||||
"net.IP": apiservercel.IP{},
|
"net.IP": apiservercel.IP{},
|
||||||
"net.CIDR": apiservercel.CIDR{},
|
"net.CIDR": apiservercel.CIDR{},
|
||||||
"kubernetes.NamedFormat": &apiservercel.Format{},
|
"kubernetes.NamedFormat": apiservercel.Format{},
|
||||||
|
"kubernetes.Semver": apiservercel.Semver{},
|
||||||
}
|
}
|
||||||
|
|
||||||
originalPanicOnUnknown := panicOnUnknown
|
originalPanicOnUnknown := panicOnUnknown
|
||||||
|
@ -133,7 +133,7 @@ func (*format) ProgramOptions() []cel.ProgramOption {
|
|||||||
return []cel.ProgramOption{}
|
return []cel.ProgramOption{}
|
||||||
}
|
}
|
||||||
|
|
||||||
var ConstantFormats map[string]*apiservercel.Format = map[string]*apiservercel.Format{
|
var ConstantFormats = map[string]apiservercel.Format{
|
||||||
"dns1123Label": {
|
"dns1123Label": {
|
||||||
Name: "DNS1123Label",
|
Name: "DNS1123Label",
|
||||||
ValidateFunc: func(s string) []string { return apimachineryvalidation.NameIsDNSLabel(s, false) },
|
ValidateFunc: func(s string) []string { return apimachineryvalidation.NameIsDNSLabel(s, false) },
|
||||||
@ -261,7 +261,7 @@ var formatLibraryDecls = map[string][]cel.FunctionOpt{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func formatValidate(arg1, arg2 ref.Val) ref.Val {
|
func formatValidate(arg1, arg2 ref.Val) ref.Val {
|
||||||
f, ok := arg1.Value().(*apiservercel.Format)
|
f, ok := arg1.Value().(apiservercel.Format)
|
||||||
if !ok {
|
if !ok {
|
||||||
return types.MaybeNoSuchOverloadErr(arg1)
|
return types.MaybeNoSuchOverloadErr(arg1)
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ var ipLib = &ip{}
|
|||||||
type ip struct{}
|
type ip struct{}
|
||||||
|
|
||||||
func (*ip) LibraryName() string {
|
func (*ip) LibraryName() string {
|
||||||
return "net.ip"
|
return "kubernetes.net.ip"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*ip) declarations() map[string][]cel.FunctionOpt {
|
func (*ip) declarations() map[string][]cel.FunctionOpt {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2023 The Kubernetes Authors.
|
Copyright 2024 The Kubernetes Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -16,7 +16,9 @@ limitations under the License.
|
|||||||
|
|
||||||
package library
|
package library
|
||||||
|
|
||||||
import "github.com/google/cel-go/cel"
|
import (
|
||||||
|
"github.com/google/cel-go/cel"
|
||||||
|
)
|
||||||
|
|
||||||
// Library represents a CEL library used by kubernetes.
|
// Library represents a CEL library used by kubernetes.
|
||||||
type Library interface {
|
type Library interface {
|
||||||
@ -42,5 +44,17 @@ func KnownLibraries() []Library {
|
|||||||
ipLib,
|
ipLib,
|
||||||
cidrsLib,
|
cidrsLib,
|
||||||
formatLib,
|
formatLib,
|
||||||
|
semverLib,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isRegisteredType(typeName string) bool {
|
||||||
|
for _, lib := range KnownLibraries() {
|
||||||
|
for _, rt := range lib.Types() {
|
||||||
|
if rt.TypeName() == typeName {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -49,7 +49,7 @@ func TestLibraryCompatibility(t *testing.T) {
|
|||||||
// Kubernetes <1.30>:
|
// Kubernetes <1.30>:
|
||||||
"ip", "family", "isUnspecified", "isLoopback", "isLinkLocalMulticast", "isLinkLocalUnicast", "isGlobalUnicast", "ip.isCanonical", "isIP", "cidr", "containsIP", "containsCIDR", "masked", "prefixLength", "isCIDR", "string",
|
"ip", "family", "isUnspecified", "isLoopback", "isLinkLocalMulticast", "isLinkLocalUnicast", "isGlobalUnicast", "ip.isCanonical", "isIP", "cidr", "containsIP", "containsCIDR", "masked", "prefixLength", "isCIDR", "string",
|
||||||
// Kubernetes <1.31>:
|
// Kubernetes <1.31>:
|
||||||
"fieldSelector", "labelSelector", "validate", "format.named",
|
"fieldSelector", "labelSelector", "validate", "format.named", "isSemver", "major", "minor", "patch", "semver",
|
||||||
// Kubernetes <1.??>:
|
// Kubernetes <1.??>:
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -101,5 +101,4 @@ func TestTypeRegistration(t *testing.T) {
|
|||||||
t.Errorf("Expected types to be registered with the %s library Type() functions, but they were not: %v", lib.LibraryName(), unregistered)
|
t.Errorf("Expected types to be registered with the %s library Type() functions, but they were not: %v", lib.LibraryName(), unregistered)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package cel_test
|
package library_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -27,7 +27,8 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
library "k8s.io/dynamic-resource-allocation/cel"
|
apiservercel "k8s.io/apiserver/pkg/cel"
|
||||||
|
library "k8s.io/apiserver/pkg/cel/library"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testSemver(t *testing.T, expr string, expectResult ref.Val, expectRuntimeErrPattern string, expectCompileErrs []string) {
|
func testSemver(t *testing.T, expr string, expectResult ref.Val, expectRuntimeErrPattern string, expectCompileErrs []string) {
|
||||||
@ -117,7 +118,7 @@ func TestSemver(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "parse",
|
name: "parse",
|
||||||
expr: `semver("1.2.3")`,
|
expr: `semver("1.2.3")`,
|
||||||
expectValue: library.Semver{Version: semver.MustParse("1.2.3")},
|
expectValue: apiservercel.Semver{Version: semver.MustParse("1.2.3")},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "parseInvalidVersion",
|
name: "parseInvalidVersion",
|
@ -14,13 +14,15 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package cel
|
package library
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/blang/semver/v4"
|
"github.com/blang/semver/v4"
|
||||||
"github.com/google/cel-go/cel"
|
"github.com/google/cel-go/cel"
|
||||||
"github.com/google/cel-go/common/types"
|
"github.com/google/cel-go/common/types"
|
||||||
"github.com/google/cel-go/common/types/ref"
|
"github.com/google/cel-go/common/types/ref"
|
||||||
|
|
||||||
|
apiservercel "k8s.io/apiserver/pkg/cel"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Semver provides a CEL function library extension for [semver.Version].
|
// Semver provides a CEL function library extension for [semver.Version].
|
||||||
@ -91,38 +93,45 @@ var semverLib = &semverLibType{}
|
|||||||
type semverLibType struct{}
|
type semverLibType struct{}
|
||||||
|
|
||||||
func (*semverLibType) LibraryName() string {
|
func (*semverLibType) LibraryName() string {
|
||||||
return "k8s.semver"
|
return "kubernetes.Semver"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*semverLibType) CompileOptions() []cel.EnvOption {
|
func (*semverLibType) Types() []*cel.Type {
|
||||||
// Defined in this function to avoid an initialization order problem.
|
return []*cel.Type{apiservercel.SemverType}
|
||||||
semverLibraryDecls := map[string][]cel.FunctionOpt{
|
}
|
||||||
|
|
||||||
|
func (*semverLibType) declarations() map[string][]cel.FunctionOpt {
|
||||||
|
return map[string][]cel.FunctionOpt{
|
||||||
"semver": {
|
"semver": {
|
||||||
cel.Overload("string_to_semver", []*cel.Type{cel.StringType}, SemverType, cel.UnaryBinding((stringToSemver))),
|
cel.Overload("string_to_semver", []*cel.Type{cel.StringType}, apiservercel.SemverType, cel.UnaryBinding((stringToSemver))),
|
||||||
},
|
},
|
||||||
"isSemver": {
|
"isSemver": {
|
||||||
cel.Overload("is_semver_string", []*cel.Type{cel.StringType}, cel.BoolType, cel.UnaryBinding(isSemver)),
|
cel.Overload("is_semver_string", []*cel.Type{cel.StringType}, cel.BoolType, cel.UnaryBinding(isSemver)),
|
||||||
},
|
},
|
||||||
"isGreaterThan": {
|
"isGreaterThan": {
|
||||||
cel.MemberOverload("semver_is_greater_than", []*cel.Type{SemverType, SemverType}, cel.BoolType, cel.BinaryBinding(semverIsGreaterThan)),
|
cel.MemberOverload("semver_is_greater_than", []*cel.Type{apiservercel.SemverType, apiservercel.SemverType}, cel.BoolType, cel.BinaryBinding(semverIsGreaterThan)),
|
||||||
},
|
},
|
||||||
"isLessThan": {
|
"isLessThan": {
|
||||||
cel.MemberOverload("semver_is_less_than", []*cel.Type{SemverType, SemverType}, cel.BoolType, cel.BinaryBinding(semverIsLessThan)),
|
cel.MemberOverload("semver_is_less_than", []*cel.Type{apiservercel.SemverType, apiservercel.SemverType}, cel.BoolType, cel.BinaryBinding(semverIsLessThan)),
|
||||||
},
|
},
|
||||||
"compareTo": {
|
"compareTo": {
|
||||||
cel.MemberOverload("semver_compare_to", []*cel.Type{SemverType, SemverType}, cel.IntType, cel.BinaryBinding(semverCompareTo)),
|
cel.MemberOverload("semver_compare_to", []*cel.Type{apiservercel.SemverType, apiservercel.SemverType}, cel.IntType, cel.BinaryBinding(semverCompareTo)),
|
||||||
},
|
},
|
||||||
"major": {
|
"major": {
|
||||||
cel.MemberOverload("semver_major", []*cel.Type{SemverType}, cel.IntType, cel.UnaryBinding(semverMajor)),
|
cel.MemberOverload("semver_major", []*cel.Type{apiservercel.SemverType}, cel.IntType, cel.UnaryBinding(semverMajor)),
|
||||||
},
|
},
|
||||||
"minor": {
|
"minor": {
|
||||||
cel.MemberOverload("semver_minor", []*cel.Type{SemverType}, cel.IntType, cel.UnaryBinding(semverMinor)),
|
cel.MemberOverload("semver_minor", []*cel.Type{apiservercel.SemverType}, cel.IntType, cel.UnaryBinding(semverMinor)),
|
||||||
},
|
},
|
||||||
"patch": {
|
"patch": {
|
||||||
cel.MemberOverload("semver_patch", []*cel.Type{SemverType}, cel.IntType, cel.UnaryBinding(semverPatch)),
|
cel.MemberOverload("semver_patch", []*cel.Type{apiservercel.SemverType}, cel.IntType, cel.UnaryBinding(semverPatch)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *semverLibType) CompileOptions() []cel.EnvOption {
|
||||||
|
// Defined in this function to avoid an initialization order problem.
|
||||||
|
semverLibraryDecls := s.declarations()
|
||||||
options := make([]cel.EnvOption, 0, len(semverLibraryDecls))
|
options := make([]cel.EnvOption, 0, len(semverLibraryDecls))
|
||||||
for name, overloads := range semverLibraryDecls {
|
for name, overloads := range semverLibraryDecls {
|
||||||
options = append(options, cel.Function(name, overloads...))
|
options = append(options, cel.Function(name, overloads...))
|
||||||
@ -168,7 +177,7 @@ func stringToSemver(arg ref.Val) ref.Val {
|
|||||||
return types.WrapErr(err)
|
return types.WrapErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Semver{Version: v}
|
return apiservercel.Semver{Version: v}
|
||||||
}
|
}
|
||||||
|
|
||||||
func semverMajor(arg ref.Val) ref.Val {
|
func semverMajor(arg ref.Val) ref.Val {
|
@ -37,6 +37,7 @@ import (
|
|||||||
celconfig "k8s.io/apiserver/pkg/apis/cel"
|
celconfig "k8s.io/apiserver/pkg/apis/cel"
|
||||||
apiservercel "k8s.io/apiserver/pkg/cel"
|
apiservercel "k8s.io/apiserver/pkg/cel"
|
||||||
"k8s.io/apiserver/pkg/cel/environment"
|
"k8s.io/apiserver/pkg/cel/environment"
|
||||||
|
"k8s.io/apiserver/pkg/cel/library"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -151,7 +152,7 @@ func getAttributeValue(attr resourceapi.DeviceAttribute) (any, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parse semantic version: %w", err)
|
return nil, fmt.Errorf("parse semantic version: %w", err)
|
||||||
}
|
}
|
||||||
return Semver{Version: v}, nil
|
return apiservercel.Semver{Version: v}, nil
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("unsupported attribute value")
|
return nil, errors.New("unsupported attribute value")
|
||||||
}
|
}
|
||||||
@ -236,7 +237,7 @@ func mustBuildEnv() *environment.EnvSet {
|
|||||||
EnvOptions: []cel.EnvOption{
|
EnvOptions: []cel.EnvOption{
|
||||||
cel.Variable(deviceVar, deviceType.CelType()),
|
cel.Variable(deviceVar, deviceType.CelType()),
|
||||||
|
|
||||||
SemverLib(),
|
library.SemverLib(),
|
||||||
|
|
||||||
// https://pkg.go.dev/github.com/google/cel-go/ext#Bindings
|
// https://pkg.go.dev/github.com/google/cel-go/ext#Bindings
|
||||||
//
|
//
|
||||||
|
Loading…
Reference in New Issue
Block a user