mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-06 10:43:56 +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 (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/cel-go/cel"
|
"github.com/google/cel-go/cel"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/util/version"
|
"k8s.io/apimachinery/pkg/util/version"
|
||||||
|
"k8s.io/apiserver/pkg/cel/library"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BenchmarkLoadBaseEnv is expected to be very fast, because a
|
// 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 {
|
func librariesInVersions(t *testing.T, vops ...VersionedOptions) []string {
|
||||||
env, err := cel.NewCustomEnv()
|
env, err := cel.NewCustomEnv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -235,6 +235,19 @@ func (*authz) LibraryName() string {
|
|||||||
return "k8s.authz"
|
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{
|
var authzLibraryDecls = map[string][]cel.FunctionOpt{
|
||||||
"path": {
|
"path": {
|
||||||
cel.MemberOverload("authorizer_path", []*cel.Type{AuthorizerType, cel.StringType}, PathCheckType,
|
cel.MemberOverload("authorizer_path", []*cel.Type{AuthorizerType, cel.StringType}, PathCheckType,
|
||||||
@ -327,6 +340,14 @@ func (*authzSelectors) LibraryName() string {
|
|||||||
return "k8s.authzSelectors"
|
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{
|
var authzSelectorsLibraryDecls = map[string][]cel.FunctionOpt{
|
||||||
"fieldSelector": {
|
"fieldSelector": {
|
||||||
cel.MemberOverload("authorizer_fieldselector", []*cel.Type{ResourceCheckType, cel.StringType}, ResourceCheckType,
|
cel.MemberOverload("authorizer_fieldselector", []*cel.Type{ResourceCheckType, cel.StringType}, ResourceCheckType,
|
||||||
|
@ -112,6 +112,14 @@ func (*cidrs) LibraryName() string {
|
|||||||
return "net.cidr"
|
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{
|
var cidrLibraryDecls = map[string][]cel.FunctionOpt{
|
||||||
"cidr": {
|
"cidr": {
|
||||||
cel.Overload("string_to_cidr", []*cel.Type{cel.StringType}, apiservercel.CIDRType,
|
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/decls"
|
||||||
"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"
|
||||||
|
|
||||||
apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
|
apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
|
||||||
"k8s.io/apimachinery/pkg/util/validation"
|
"k8s.io/apimachinery/pkg/util/validation"
|
||||||
apiservercel "k8s.io/apiserver/pkg/cel"
|
apiservercel "k8s.io/apiserver/pkg/cel"
|
||||||
@ -93,6 +94,14 @@ func (*format) LibraryName() string {
|
|||||||
return "format"
|
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 {
|
func ZeroArgumentFunctionBinding(binding func() ref.Val) decls.OverloadOpt {
|
||||||
return func(o *decls.OverloadDecl) (*decls.OverloadDecl, error) {
|
return func(o *decls.OverloadDecl) (*decls.OverloadDecl, error) {
|
||||||
wrapped, err := decls.FunctionBinding(func(values ...ref.Val) ref.Val { return binding() })(o)
|
wrapped, err := decls.FunctionBinding(func(values ...ref.Val) ref.Val { return binding() })(o)
|
||||||
|
@ -135,6 +135,14 @@ func (*ip) LibraryName() string {
|
|||||||
return "net.ip"
|
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{
|
var ipLibraryDecls = map[string][]cel.FunctionOpt{
|
||||||
"ip": {
|
"ip": {
|
||||||
cel.Overload("string_to_ip", []*cel.Type{cel.StringType}, apiservercel.IPType,
|
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
|
package library
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/google/cel-go/cel"
|
"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"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLibraryCompatibility(t *testing.T) {
|
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]()
|
functionNames := sets.New[string]()
|
||||||
for _, lib := range libs {
|
for _, lib := range KnownLibraries() {
|
||||||
for name := range lib {
|
for name := range lib.declarations() {
|
||||||
functionNames[name] = struct{}{}
|
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)
|
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"
|
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")
|
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.
|
// 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"
|
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{
|
var quantityLibraryDecls = map[string][]cel.FunctionOpt{
|
||||||
"quantity": {
|
"quantity": {
|
||||||
cel.Overload("string_to_quantity", []*cel.Type{cel.StringType}, apiservercel.QuantityType, cel.UnaryBinding((stringToQuantity))),
|
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"
|
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{
|
var regexLibraryDecls = map[string][]cel.FunctionOpt{
|
||||||
"find": {
|
"find": {
|
||||||
cel.MemberOverload("string_find_string", []*cel.Type{cel.StringType, cel.StringType}, cel.StringType,
|
cel.MemberOverload("string_find_string", []*cel.Type{cel.StringType, cel.StringType}, cel.StringType,
|
||||||
|
@ -116,6 +116,14 @@ func (*urls) LibraryName() string {
|
|||||||
return "k8s.urls"
|
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{
|
var urlLibraryDecls = map[string][]cel.FunctionOpt{
|
||||||
"url": {
|
"url": {
|
||||||
cel.Overload("string_to_url", []*cel.Type{cel.StringType}, apiservercel.URLType,
|
cel.Overload("string_to_url", []*cel.Type{cel.StringType}, apiservercel.URLType,
|
||||||
|
Loading…
Reference in New Issue
Block a user