mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-05 02:09:56 +00:00
Move CEL env initialization out of package init()
This ensures compatibility version and feature gates can be initialized before cached CEL environments are created.
This commit is contained in:
parent
1d2ad282cf
commit
03d48b7683
@ -21,6 +21,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
genericvalidation "k8s.io/apimachinery/pkg/api/validation"
|
genericvalidation "k8s.io/apimachinery/pkg/api/validation"
|
||||||
"k8s.io/apimachinery/pkg/api/validation/path"
|
"k8s.io/apimachinery/pkg/api/validation/path"
|
||||||
@ -1066,9 +1067,9 @@ func validateMatchConditionsExpression(expression string, opts validationOptions
|
|||||||
}
|
}
|
||||||
var compiler plugincel.Compiler
|
var compiler plugincel.Compiler
|
||||||
if opts.strictCostEnforcement {
|
if opts.strictCostEnforcement {
|
||||||
compiler = strictStatelessCELCompiler
|
compiler = getStrictStatelessCELCompiler()
|
||||||
} else {
|
} else {
|
||||||
compiler = nonStrictStatelessCELCompiler
|
compiler = getNonStrictStatelessCELCompiler()
|
||||||
}
|
}
|
||||||
return validateCELCondition(compiler, &matchconditions.MatchCondition{
|
return validateCELCondition(compiler, &matchconditions.MatchCondition{
|
||||||
Expression: expression,
|
Expression: expression,
|
||||||
@ -1270,15 +1271,34 @@ func validateFieldRef(fieldRef string, fldPath *field.Path) field.ErrorList {
|
|||||||
// variable composition is not allowed, for example, when validating MatchConditions.
|
// variable composition is not allowed, for example, when validating MatchConditions.
|
||||||
// strictStatelessCELCompiler is a cel Compiler that enforces strict cost enforcement.
|
// strictStatelessCELCompiler is a cel Compiler that enforces strict cost enforcement.
|
||||||
// nonStrictStatelessCELCompiler is a cel Compiler that does not enforce strict cost enforcement.
|
// nonStrictStatelessCELCompiler is a cel Compiler that does not enforce strict cost enforcement.
|
||||||
var strictStatelessCELCompiler = plugincel.NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
|
var (
|
||||||
var nonStrictStatelessCELCompiler = plugincel.NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), false))
|
lazyStrictStatelessCELCompilerInit sync.Once
|
||||||
|
lazyStrictStatelessCELCompiler plugincel.Compiler
|
||||||
|
|
||||||
|
lazyNonStrictStatelessCELCompilerInit sync.Once
|
||||||
|
lazyNonStrictStatelessCELCompiler plugincel.Compiler
|
||||||
|
)
|
||||||
|
|
||||||
|
func getStrictStatelessCELCompiler() plugincel.Compiler {
|
||||||
|
lazyStrictStatelessCELCompilerInit.Do(func() {
|
||||||
|
lazyStrictStatelessCELCompiler = plugincel.NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
|
||||||
|
})
|
||||||
|
return lazyStrictStatelessCELCompiler
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNonStrictStatelessCELCompiler() plugincel.Compiler {
|
||||||
|
lazyNonStrictStatelessCELCompilerInit.Do(func() {
|
||||||
|
lazyNonStrictStatelessCELCompiler = plugincel.NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), false))
|
||||||
|
})
|
||||||
|
return lazyNonStrictStatelessCELCompiler
|
||||||
|
}
|
||||||
|
|
||||||
func createCompiler(allowComposition, strictCost bool) plugincel.Compiler {
|
func createCompiler(allowComposition, strictCost bool) plugincel.Compiler {
|
||||||
if !allowComposition {
|
if !allowComposition {
|
||||||
if strictCost {
|
if strictCost {
|
||||||
return strictStatelessCELCompiler
|
return getStrictStatelessCELCompiler()
|
||||||
} else {
|
} else {
|
||||||
return nonStrictStatelessCELCompiler
|
return getNonStrictStatelessCELCompiler()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compiler, err := plugincel.NewCompositedCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), strictCost))
|
compiler, err := plugincel.NewCompositedCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), strictCost))
|
||||||
|
@ -3425,14 +3425,16 @@ func TestValidateValidatingAdmissionPolicyUpdate(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if strictCost {
|
if strictCost {
|
||||||
strictStatelessCELCompiler = plugincel.NewCompiler(extended)
|
originalCompiler := getStrictStatelessCELCompiler()
|
||||||
|
lazyStrictStatelessCELCompiler = plugincel.NewCompiler(extended)
|
||||||
defer func() {
|
defer func() {
|
||||||
strictStatelessCELCompiler = plugincel.NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), strictCost))
|
lazyStrictStatelessCELCompiler = originalCompiler
|
||||||
}()
|
}()
|
||||||
} else {
|
} else {
|
||||||
nonStrictStatelessCELCompiler = plugincel.NewCompiler(extended)
|
originalCompiler := getNonStrictStatelessCELCompiler()
|
||||||
|
lazyNonStrictStatelessCELCompiler = plugincel.NewCompiler(extended)
|
||||||
defer func() {
|
defer func() {
|
||||||
nonStrictStatelessCELCompiler = plugincel.NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), strictCost))
|
lazyNonStrictStatelessCELCompiler = originalCompiler
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ func validateSelector(opts Options, selector string, fldPath *field.Path) field.
|
|||||||
if opts.StoredExpressions {
|
if opts.StoredExpressions {
|
||||||
envType = environment.StoredExpressions
|
envType = environment.StoredExpressions
|
||||||
}
|
}
|
||||||
result := namedresourcescel.Compiler.CompileCELExpression(selector, envType)
|
result := namedresourcescel.GetCompiler().CompileCELExpression(selector, envType)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
allErrs = append(allErrs, convertCELErrorToValidationError(fldPath, selector, result.Error))
|
allErrs = append(allErrs, convertCELErrorToValidationError(fldPath, selector, result.Error))
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ func AddAllocation(m *Model, result *resourceapi.NamedResourcesAllocationResult)
|
|||||||
func NewClaimController(filter *resourceapi.NamedResourcesFilter, requests []*resourceapi.NamedResourcesRequest) (*Controller, error) {
|
func NewClaimController(filter *resourceapi.NamedResourcesFilter, requests []*resourceapi.NamedResourcesRequest) (*Controller, error) {
|
||||||
c := &Controller{}
|
c := &Controller{}
|
||||||
if filter != nil {
|
if filter != nil {
|
||||||
compilation := cel.Compiler.CompileCELExpression(filter.Selector, environment.StoredExpressions)
|
compilation := cel.GetCompiler().CompileCELExpression(filter.Selector, environment.StoredExpressions)
|
||||||
if compilation.Error != nil {
|
if compilation.Error != nil {
|
||||||
// Shouldn't happen because of validation.
|
// Shouldn't happen because of validation.
|
||||||
return nil, fmt.Errorf("compile class filter CEL expression: %w", compilation.Error)
|
return nil, fmt.Errorf("compile class filter CEL expression: %w", compilation.Error)
|
||||||
@ -76,7 +76,7 @@ func NewClaimController(filter *resourceapi.NamedResourcesFilter, requests []*re
|
|||||||
c.filter = &compilation
|
c.filter = &compilation
|
||||||
}
|
}
|
||||||
for _, request := range requests {
|
for _, request := range requests {
|
||||||
compilation := cel.Compiler.CompileCELExpression(request.Selector, environment.StoredExpressions)
|
compilation := cel.GetCompiler().CompileCELExpression(request.Selector, environment.StoredExpressions)
|
||||||
if compilation.Error != nil {
|
if compilation.Error != nil {
|
||||||
// Shouldn't happen because of validation.
|
// Shouldn't happen because of validation.
|
||||||
return nil, fmt.Errorf("compile request CEL expression: %w", compilation.Error)
|
return nil, fmt.Errorf("compile request CEL expression: %w", compilation.Error)
|
||||||
|
@ -19,6 +19,7 @@ package validating
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
|
"sync"
|
||||||
|
|
||||||
v1 "k8s.io/api/admissionregistration/v1"
|
v1 "k8s.io/api/admissionregistration/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
@ -44,24 +45,35 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
compositionEnvTemplateWithStrictCost *cel.CompositionEnv = func() *cel.CompositionEnv {
|
lazyCompositionEnvTemplateWithStrictCostInit sync.Once
|
||||||
compositionEnvTemplateWithStrictCost, err := cel.NewCompositionEnv(cel.VariablesTypeName, environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
|
lazyCompositionEnvTemplateWithStrictCost *cel.CompositionEnv
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return compositionEnvTemplateWithStrictCost
|
lazyCompositionEnvTemplateWithoutStrictCostInit sync.Once
|
||||||
}()
|
lazyCompositionEnvTemplateWithoutStrictCost *cel.CompositionEnv
|
||||||
compositionEnvTemplateWithoutStrictCost *cel.CompositionEnv = func() *cel.CompositionEnv {
|
|
||||||
compositionEnvTemplateWithoutStrictCost, err := cel.NewCompositionEnv(cel.VariablesTypeName, environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), false))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return compositionEnvTemplateWithoutStrictCost
|
|
||||||
}()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func getCompositionEnvTemplateWithStrictCost() *cel.CompositionEnv {
|
||||||
|
lazyCompositionEnvTemplateWithStrictCostInit.Do(func() {
|
||||||
|
env, err := cel.NewCompositionEnv(cel.VariablesTypeName, environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
lazyCompositionEnvTemplateWithStrictCost = env
|
||||||
|
})
|
||||||
|
return lazyCompositionEnvTemplateWithStrictCost
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCompositionEnvTemplateWithoutStrictCost() *cel.CompositionEnv {
|
||||||
|
lazyCompositionEnvTemplateWithoutStrictCostInit.Do(func() {
|
||||||
|
env, err := cel.NewCompositionEnv(cel.VariablesTypeName, environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), false))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
lazyCompositionEnvTemplateWithoutStrictCost = env
|
||||||
|
})
|
||||||
|
return lazyCompositionEnvTemplateWithoutStrictCost
|
||||||
|
}
|
||||||
|
|
||||||
// Register registers a plugin
|
// Register registers a plugin
|
||||||
func Register(plugins *admission.Plugins) {
|
func Register(plugins *admission.Plugins) {
|
||||||
plugins.Register(PluginName, func(configFile io.Reader) (admission.Interface, error) {
|
plugins.Register(PluginName, func(configFile io.Reader) (admission.Interface, error) {
|
||||||
@ -131,9 +143,9 @@ func compilePolicy(policy *Policy) Validator {
|
|||||||
matchConditions := policy.Spec.MatchConditions
|
matchConditions := policy.Spec.MatchConditions
|
||||||
var compositionEnvTemplate *cel.CompositionEnv
|
var compositionEnvTemplate *cel.CompositionEnv
|
||||||
if strictCost {
|
if strictCost {
|
||||||
compositionEnvTemplate = compositionEnvTemplateWithStrictCost
|
compositionEnvTemplate = getCompositionEnvTemplateWithStrictCost()
|
||||||
} else {
|
} else {
|
||||||
compositionEnvTemplate = compositionEnvTemplateWithoutStrictCost
|
compositionEnvTemplate = getCompositionEnvTemplateWithoutStrictCost()
|
||||||
}
|
}
|
||||||
filterCompiler := cel.NewCompositedCompilerFromTemplate(compositionEnvTemplate)
|
filterCompiler := cel.NewCompositedCompilerFromTemplate(compositionEnvTemplate)
|
||||||
filterCompiler.CompileAndStoreVariables(convertv1beta1Variables(policy.Spec.Variables), optionalVars, environment.StoredExpressions)
|
filterCompiler.CompileAndStoreVariables(convertv1beta1Variables(policy.Spec.Variables), optionalVars, environment.StoredExpressions)
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/blang/semver/v4"
|
"github.com/blang/semver/v4"
|
||||||
"github.com/google/cel-go/cel"
|
"github.com/google/cel-go/cel"
|
||||||
@ -38,9 +39,17 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Compiler = newCompiler()
|
lazyCompilerInit sync.Once
|
||||||
|
lazyCompiler *compiler
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func GetCompiler() *compiler {
|
||||||
|
lazyCompilerInit.Do(func() {
|
||||||
|
lazyCompiler = newCompiler()
|
||||||
|
})
|
||||||
|
return lazyCompiler
|
||||||
|
}
|
||||||
|
|
||||||
// CompilationResult represents a compiled expression.
|
// CompilationResult represents a compiled expression.
|
||||||
type CompilationResult struct {
|
type CompilationResult struct {
|
||||||
Program cel.Program
|
Program cel.Program
|
||||||
|
@ -124,7 +124,7 @@ attributes.stringslice["stringslice"].isSorted()`,
|
|||||||
} {
|
} {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
_, ctx := ktesting.NewTestContext(t)
|
_, ctx := ktesting.NewTestContext(t)
|
||||||
result := Compiler.CompileCELExpression(scenario.expression, environment.StoredExpressions)
|
result := GetCompiler().CompileCELExpression(scenario.expression, environment.StoredExpressions)
|
||||||
if scenario.expectCompileError != "" && result.Error == nil {
|
if scenario.expectCompileError != "" && result.Error == nil {
|
||||||
t.Fatalf("expected compile error %q, got none", scenario.expectCompileError)
|
t.Fatalf("expected compile error %q, got none", scenario.expectCompileError)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user