mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-05 10:19:50 +00:00
add a type for each CEL library, register all types
This commit is contained in:
parent
f1a922c8e6
commit
d2affe3048
@ -18,11 +18,14 @@ package environment
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/cel-go/cel"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/apiserver/pkg/cel/library"
|
||||
)
|
||||
|
||||
// BenchmarkLoadBaseEnv is expected to be very fast, because a
|
||||
@ -112,6 +115,28 @@ func TestLibraryCoverage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestKnownLibraries(t *testing.T) {
|
||||
known := sets.New[string]()
|
||||
used := sets.New[string]()
|
||||
|
||||
for _, lib := range library.KnownLibraries() {
|
||||
known.Insert(lib.LibraryName())
|
||||
}
|
||||
for _, libName := range MustBaseEnvSet(version.MajorMinor(1, 0), true).storedExpressions.Libraries() {
|
||||
if strings.HasPrefix(libName, "cel.lib") { // ignore core libs
|
||||
continue
|
||||
}
|
||||
used.Insert(libName)
|
||||
}
|
||||
|
||||
unexpected := used.Difference(known)
|
||||
|
||||
if len(unexpected) != 0 {
|
||||
t.Errorf("Expected all libraries in the base environment to be included k8s.io/apiserver/pkg/cel/library's KnownLibraries, but found missing libraries: %v", unexpected)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func librariesInVersions(t *testing.T, vops ...VersionedOptions) []string {
|
||||
env, err := cel.NewCustomEnv()
|
||||
if err != nil {
|
||||
|
@ -235,6 +235,19 @@ func (*authz) LibraryName() string {
|
||||
return "k8s.authz"
|
||||
}
|
||||
|
||||
func (*authz) Types() []*cel.Type {
|
||||
return []*cel.Type{
|
||||
AuthorizerType,
|
||||
PathCheckType,
|
||||
GroupCheckType,
|
||||
ResourceCheckType,
|
||||
DecisionType}
|
||||
}
|
||||
|
||||
func (*authz) declarations() map[string][]cel.FunctionOpt {
|
||||
return authzLibraryDecls
|
||||
}
|
||||
|
||||
var authzLibraryDecls = map[string][]cel.FunctionOpt{
|
||||
"path": {
|
||||
cel.MemberOverload("authorizer_path", []*cel.Type{AuthorizerType, cel.StringType}, PathCheckType,
|
||||
@ -327,6 +340,14 @@ func (*authzSelectors) LibraryName() string {
|
||||
return "k8s.authzSelectors"
|
||||
}
|
||||
|
||||
func (*authzSelectors) Types() []*cel.Type {
|
||||
return []*cel.Type{ResourceCheckType}
|
||||
}
|
||||
|
||||
func (*authzSelectors) declarations() map[string][]cel.FunctionOpt {
|
||||
return authzSelectorsLibraryDecls
|
||||
}
|
||||
|
||||
var authzSelectorsLibraryDecls = map[string][]cel.FunctionOpt{
|
||||
"fieldSelector": {
|
||||
cel.MemberOverload("authorizer_fieldselector", []*cel.Type{ResourceCheckType, cel.StringType}, ResourceCheckType,
|
||||
|
@ -112,6 +112,14 @@ func (*cidrs) LibraryName() string {
|
||||
return "net.cidr"
|
||||
}
|
||||
|
||||
func (*cidrs) declarations() map[string][]cel.FunctionOpt {
|
||||
return cidrLibraryDecls
|
||||
}
|
||||
|
||||
func (*cidrs) Types() []*cel.Type {
|
||||
return []*cel.Type{apiservercel.CIDRType, apiservercel.IPType}
|
||||
}
|
||||
|
||||
var cidrLibraryDecls = map[string][]cel.FunctionOpt{
|
||||
"cidr": {
|
||||
cel.Overload("string_to_cidr", []*cel.Type{cel.StringType}, apiservercel.CIDRType,
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"github.com/google/cel-go/common/decls"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
|
||||
apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
apiservercel "k8s.io/apiserver/pkg/cel"
|
||||
@ -93,6 +94,14 @@ func (*format) LibraryName() string {
|
||||
return "format"
|
||||
}
|
||||
|
||||
func (*format) Types() []*cel.Type {
|
||||
return []*cel.Type{apiservercel.FormatType}
|
||||
}
|
||||
|
||||
func (*format) declarations() map[string][]cel.FunctionOpt {
|
||||
return formatLibraryDecls
|
||||
}
|
||||
|
||||
func ZeroArgumentFunctionBinding(binding func() ref.Val) decls.OverloadOpt {
|
||||
return func(o *decls.OverloadDecl) (*decls.OverloadDecl, error) {
|
||||
wrapped, err := decls.FunctionBinding(func(values ...ref.Val) ref.Val { return binding() })(o)
|
||||
|
@ -135,6 +135,14 @@ func (*ip) LibraryName() string {
|
||||
return "net.ip"
|
||||
}
|
||||
|
||||
func (*ip) declarations() map[string][]cel.FunctionOpt {
|
||||
return ipLibraryDecls
|
||||
}
|
||||
|
||||
func (*ip) Types() []*cel.Type {
|
||||
return []*cel.Type{apiservercel.IPType}
|
||||
}
|
||||
|
||||
var ipLibraryDecls = map[string][]cel.FunctionOpt{
|
||||
"ip": {
|
||||
cel.Overload("string_to_ip", []*cel.Type{cel.StringType}, apiservercel.IPType,
|
||||
|
46
staging/src/k8s.io/apiserver/pkg/cel/library/libraries.go
Normal file
46
staging/src/k8s.io/apiserver/pkg/cel/library/libraries.go
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright 2023 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package library
|
||||
|
||||
import "github.com/google/cel-go/cel"
|
||||
|
||||
// Library represents a CEL library used by kubernetes.
|
||||
type Library interface {
|
||||
// SingletonLibrary provides the library name and ensures the library can be safely registered into environments.
|
||||
cel.SingletonLibrary
|
||||
|
||||
// Types provides all custom types introduced by the library.
|
||||
Types() []*cel.Type
|
||||
|
||||
// declarations returns all function declarations provided by the library.
|
||||
declarations() map[string][]cel.FunctionOpt
|
||||
}
|
||||
|
||||
// KnownLibraries returns all libraries used in Kubernetes.
|
||||
func KnownLibraries() []Library {
|
||||
return []Library{
|
||||
authzLib,
|
||||
authzSelectorsLib,
|
||||
listsLib,
|
||||
regexLib,
|
||||
urlsLib,
|
||||
quantityLib,
|
||||
ipLib,
|
||||
cidrsLib,
|
||||
formatLib,
|
||||
}
|
||||
}
|
@ -17,19 +17,18 @@ limitations under the License.
|
||||
package library
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/common/decls"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
func TestLibraryCompatibility(t *testing.T) {
|
||||
var libs []map[string][]cel.FunctionOpt
|
||||
libs = append(libs, authzLibraryDecls, listsLibraryDecls, regexLibraryDecls, urlLibraryDecls, quantityLibraryDecls, ipLibraryDecls, cidrLibraryDecls, formatLibraryDecls, authzSelectorsLibraryDecls)
|
||||
functionNames := sets.New[string]()
|
||||
for _, lib := range libs {
|
||||
for name := range lib {
|
||||
for _, lib := range KnownLibraries() {
|
||||
for name := range lib.declarations() {
|
||||
functionNames[name] = struct{}{}
|
||||
}
|
||||
}
|
||||
@ -66,3 +65,33 @@ func TestLibraryCompatibility(t *testing.T) {
|
||||
t.Errorf("Expected all functions in the libraries to be assigned to a kubernetes release, but found the missing function names: %v", missing)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypeRegistration(t *testing.T) {
|
||||
for _, lib := range KnownLibraries() {
|
||||
registeredTypes := sets.New[*cel.Type]()
|
||||
usedTypes := sets.New[*cel.Type]()
|
||||
// scan all registered functions
|
||||
for _, fn := range lib.declarations() {
|
||||
testFn, err := decls.NewFunction("test", fn...)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, o := range testFn.OverloadDecls() {
|
||||
for _, at := range o.ArgTypes() {
|
||||
switch at.Kind() {
|
||||
case types.OpaqueKind, types.StructKind:
|
||||
usedTypes.Insert(at)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, t := range lib.Types() {
|
||||
registeredTypes.Insert(t)
|
||||
}
|
||||
unregistered := usedTypes.Difference(registeredTypes)
|
||||
if len(unregistered) != 0 {
|
||||
t.Errorf("Expected types to be registered with the %s library Type() functions, but they were not: %v", lib.LibraryName(), unregistered)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -99,6 +99,14 @@ func (*lists) LibraryName() string {
|
||||
return "k8s.lists"
|
||||
}
|
||||
|
||||
func (*lists) Types() []*cel.Type {
|
||||
return []*cel.Type{}
|
||||
}
|
||||
|
||||
func (*lists) declarations() map[string][]cel.FunctionOpt {
|
||||
return listsLibraryDecls
|
||||
}
|
||||
|
||||
var paramA = cel.TypeParamType("A")
|
||||
|
||||
// CEL typeParams can be used to constraint to a specific trait (e.g. traits.ComparableType) if the 1st operand is the type to constrain.
|
||||
|
@ -146,6 +146,14 @@ func (*quantity) LibraryName() string {
|
||||
return "k8s.quantity"
|
||||
}
|
||||
|
||||
func (*quantity) Types() []*cel.Type {
|
||||
return []*cel.Type{apiservercel.QuantityType}
|
||||
}
|
||||
|
||||
func (*quantity) declarations() map[string][]cel.FunctionOpt {
|
||||
return quantityLibraryDecls
|
||||
}
|
||||
|
||||
var quantityLibraryDecls = map[string][]cel.FunctionOpt{
|
||||
"quantity": {
|
||||
cel.Overload("string_to_quantity", []*cel.Type{cel.StringType}, apiservercel.QuantityType, cel.UnaryBinding((stringToQuantity))),
|
||||
|
@ -55,6 +55,14 @@ func (*regex) LibraryName() string {
|
||||
return "k8s.regex"
|
||||
}
|
||||
|
||||
func (*regex) Types() []*cel.Type {
|
||||
return []*cel.Type{}
|
||||
}
|
||||
|
||||
func (*regex) declarations() map[string][]cel.FunctionOpt {
|
||||
return regexLibraryDecls
|
||||
}
|
||||
|
||||
var regexLibraryDecls = map[string][]cel.FunctionOpt{
|
||||
"find": {
|
||||
cel.MemberOverload("string_find_string", []*cel.Type{cel.StringType, cel.StringType}, cel.StringType,
|
||||
|
@ -116,6 +116,14 @@ func (*urls) LibraryName() string {
|
||||
return "k8s.urls"
|
||||
}
|
||||
|
||||
func (*urls) Types() []*cel.Type {
|
||||
return []*cel.Type{apiservercel.URLType}
|
||||
}
|
||||
|
||||
func (*urls) declarations() map[string][]cel.FunctionOpt {
|
||||
return urlLibraryDecls
|
||||
}
|
||||
|
||||
var urlLibraryDecls = map[string][]cel.FunctionOpt{
|
||||
"url": {
|
||||
cel.Overload("string_to_url", []*cel.Type{cel.StringType}, apiservercel.URLType,
|
||||
|
Loading…
Reference in New Issue
Block a user