mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 18:53:35 +00:00
rebase: update K8s packages to v0.32.1
Update K8s packages in go.mod to v0.32.1 Signed-off-by: Praveen M <m.praveen@ibm.com>
This commit is contained in:
190
vendor/k8s.io/apiserver/pkg/admission/plugin/cel/activation.go
generated
vendored
Normal file
190
vendor/k8s.io/apiserver/pkg/admission/plugin/cel/activation.go
generated
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
Copyright 2024 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 cel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/google/cel-go/interpreter"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/cel"
|
||||
"k8s.io/apiserver/pkg/cel/library"
|
||||
)
|
||||
|
||||
// newActivation creates an activation for CEL admission plugins from the given request, admission chain and
|
||||
// variable binding information.
|
||||
func newActivation(compositionCtx CompositionContext, versionedAttr *admission.VersionedAttributes, request *admissionv1.AdmissionRequest, inputs OptionalVariableBindings, namespace *v1.Namespace) (*evaluationActivation, error) {
|
||||
oldObjectVal, err := objectToResolveVal(versionedAttr.VersionedOldObject)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to prepare oldObject variable for evaluation: %w", err)
|
||||
}
|
||||
objectVal, err := objectToResolveVal(versionedAttr.VersionedObject)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to prepare object variable for evaluation: %w", err)
|
||||
}
|
||||
var paramsVal, authorizerVal, requestResourceAuthorizerVal any
|
||||
if inputs.VersionedParams != nil {
|
||||
paramsVal, err = objectToResolveVal(inputs.VersionedParams)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to prepare params variable for evaluation: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if inputs.Authorizer != nil {
|
||||
authorizerVal = library.NewAuthorizerVal(versionedAttr.GetUserInfo(), inputs.Authorizer)
|
||||
requestResourceAuthorizerVal = library.NewResourceAuthorizerVal(versionedAttr.GetUserInfo(), inputs.Authorizer, versionedAttr)
|
||||
}
|
||||
|
||||
requestVal, err := convertObjectToUnstructured(request)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to prepare request variable for evaluation: %w", err)
|
||||
}
|
||||
namespaceVal, err := objectToResolveVal(namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to prepare namespace variable for evaluation: %w", err)
|
||||
}
|
||||
va := &evaluationActivation{
|
||||
object: objectVal,
|
||||
oldObject: oldObjectVal,
|
||||
params: paramsVal,
|
||||
request: requestVal.Object,
|
||||
namespace: namespaceVal,
|
||||
authorizer: authorizerVal,
|
||||
requestResourceAuthorizer: requestResourceAuthorizerVal,
|
||||
}
|
||||
|
||||
// composition is an optional feature that only applies for ValidatingAdmissionPolicy and MutatingAdmissionPolicy.
|
||||
if compositionCtx != nil {
|
||||
va.variables = compositionCtx.Variables(va)
|
||||
}
|
||||
return va, nil
|
||||
}
|
||||
|
||||
type evaluationActivation struct {
|
||||
object, oldObject, params, request, namespace, authorizer, requestResourceAuthorizer, variables interface{}
|
||||
}
|
||||
|
||||
// ResolveName returns a value from the activation by qualified name, or false if the name
|
||||
// could not be found.
|
||||
func (a *evaluationActivation) ResolveName(name string) (interface{}, bool) {
|
||||
switch name {
|
||||
case ObjectVarName:
|
||||
return a.object, true
|
||||
case OldObjectVarName:
|
||||
return a.oldObject, true
|
||||
case ParamsVarName:
|
||||
return a.params, true // params may be null
|
||||
case RequestVarName:
|
||||
return a.request, true
|
||||
case NamespaceVarName:
|
||||
return a.namespace, true
|
||||
case AuthorizerVarName:
|
||||
return a.authorizer, a.authorizer != nil
|
||||
case RequestResourceAuthorizerVarName:
|
||||
return a.requestResourceAuthorizer, a.requestResourceAuthorizer != nil
|
||||
case VariableVarName: // variables always present
|
||||
return a.variables, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
// Parent returns the parent of the current activation, may be nil.
|
||||
// If non-nil, the parent will be searched during resolve calls.
|
||||
func (a *evaluationActivation) Parent() interpreter.Activation {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Evaluate runs a compiled CEL admission plugin expression using the provided activation and CEL
|
||||
// runtime cost budget.
|
||||
func (a *evaluationActivation) Evaluate(ctx context.Context, compositionCtx CompositionContext, compilationResult CompilationResult, remainingBudget int64) (EvaluationResult, int64, error) {
|
||||
var evaluation = EvaluationResult{}
|
||||
if compilationResult.ExpressionAccessor == nil { // in case of placeholder
|
||||
return evaluation, remainingBudget, nil
|
||||
}
|
||||
|
||||
evaluation.ExpressionAccessor = compilationResult.ExpressionAccessor
|
||||
if compilationResult.Error != nil {
|
||||
evaluation.Error = &cel.Error{
|
||||
Type: cel.ErrorTypeInvalid,
|
||||
Detail: fmt.Sprintf("compilation error: %v", compilationResult.Error),
|
||||
Cause: compilationResult.Error,
|
||||
}
|
||||
return evaluation, remainingBudget, nil
|
||||
}
|
||||
if compilationResult.Program == nil {
|
||||
evaluation.Error = &cel.Error{
|
||||
Type: cel.ErrorTypeInternal,
|
||||
Detail: "unexpected internal error compiling expression",
|
||||
}
|
||||
return evaluation, remainingBudget, nil
|
||||
}
|
||||
t1 := time.Now()
|
||||
evalResult, evalDetails, err := compilationResult.Program.ContextEval(ctx, a)
|
||||
// budget may be spent due to lazy evaluation of composited variables
|
||||
if compositionCtx != nil {
|
||||
compositionCost := compositionCtx.GetAndResetCost()
|
||||
if compositionCost > remainingBudget {
|
||||
return evaluation, -1, &cel.Error{
|
||||
Type: cel.ErrorTypeInvalid,
|
||||
Detail: "validation failed due to running out of cost budget, no further validation rules will be run",
|
||||
Cause: cel.ErrOutOfBudget,
|
||||
}
|
||||
}
|
||||
remainingBudget -= compositionCost
|
||||
}
|
||||
elapsed := time.Since(t1)
|
||||
evaluation.Elapsed = elapsed
|
||||
if evalDetails == nil {
|
||||
return evaluation, -1, &cel.Error{
|
||||
Type: cel.ErrorTypeInternal,
|
||||
Detail: fmt.Sprintf("runtime cost could not be calculated for expression: %v, no further expression will be run", compilationResult.ExpressionAccessor.GetExpression()),
|
||||
}
|
||||
} else {
|
||||
rtCost := evalDetails.ActualCost()
|
||||
if rtCost == nil {
|
||||
return evaluation, -1, &cel.Error{
|
||||
Type: cel.ErrorTypeInvalid,
|
||||
Detail: fmt.Sprintf("runtime cost could not be calculated for expression: %v, no further expression will be run", compilationResult.ExpressionAccessor.GetExpression()),
|
||||
Cause: cel.ErrOutOfBudget,
|
||||
}
|
||||
} else {
|
||||
if *rtCost > math.MaxInt64 || int64(*rtCost) > remainingBudget {
|
||||
return evaluation, -1, &cel.Error{
|
||||
Type: cel.ErrorTypeInvalid,
|
||||
Detail: "validation failed due to running out of cost budget, no further validation rules will be run",
|
||||
Cause: cel.ErrOutOfBudget,
|
||||
}
|
||||
}
|
||||
remainingBudget -= int64(*rtCost)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
evaluation.Error = &cel.Error{
|
||||
Type: cel.ErrorTypeInvalid,
|
||||
Detail: fmt.Sprintf("expression '%v' resulted in error: %v", compilationResult.ExpressionAccessor.GetExpression(), err),
|
||||
}
|
||||
} else {
|
||||
evaluation.EvalResult = evalResult
|
||||
}
|
||||
return evaluation, remainingBudget, nil
|
||||
}
|
110
vendor/k8s.io/apiserver/pkg/admission/plugin/cel/compile.go
generated
vendored
110
vendor/k8s.io/apiserver/pkg/admission/plugin/cel/compile.go
generated
vendored
@ -24,8 +24,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
celconfig "k8s.io/apiserver/pkg/apis/cel"
|
||||
apiservercel "k8s.io/apiserver/pkg/cel"
|
||||
"k8s.io/apiserver/pkg/cel/common"
|
||||
"k8s.io/apiserver/pkg/cel/environment"
|
||||
"k8s.io/apiserver/pkg/cel/library"
|
||||
"k8s.io/apiserver/pkg/cel/mutation"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -186,7 +188,7 @@ func (c compiler) CompileCELExpression(expressionAccessor ExpressionAccessor, op
|
||||
found := false
|
||||
returnTypes := expressionAccessor.ReturnTypes()
|
||||
for _, returnType := range returnTypes {
|
||||
if ast.OutputType() == returnType || cel.AnyType == returnType {
|
||||
if ast.OutputType().IsExactType(returnType) || cel.AnyType.IsExactType(returnType) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
@ -194,9 +196,9 @@ func (c compiler) CompileCELExpression(expressionAccessor ExpressionAccessor, op
|
||||
if !found {
|
||||
var reason string
|
||||
if len(returnTypes) == 1 {
|
||||
reason = fmt.Sprintf("must evaluate to %v", returnTypes[0].String())
|
||||
reason = fmt.Sprintf("must evaluate to %v but got %v", returnTypes[0].String(), ast.OutputType().String())
|
||||
} else {
|
||||
reason = fmt.Sprintf("must evaluate to one of %v", returnTypes)
|
||||
reason = fmt.Sprintf("must evaluate to one of %v but got %v", returnTypes, ast.OutputType().String())
|
||||
}
|
||||
|
||||
return resultError(reason, apiservercel.ErrorTypeInvalid, nil)
|
||||
@ -226,46 +228,78 @@ func mustBuildEnvs(baseEnv *environment.EnvSet) variableDeclEnvs {
|
||||
envs := make(variableDeclEnvs, 8) // since the number of variable combinations is small, pre-build a environment for each
|
||||
for _, hasParams := range []bool{false, true} {
|
||||
for _, hasAuthorizer := range []bool{false, true} {
|
||||
var err error
|
||||
for _, strictCost := range []bool{false, true} {
|
||||
var envOpts []cel.EnvOption
|
||||
if hasParams {
|
||||
envOpts = append(envOpts, cel.Variable(ParamsVarName, cel.DynType))
|
||||
}
|
||||
if hasAuthorizer {
|
||||
envOpts = append(envOpts,
|
||||
cel.Variable(AuthorizerVarName, library.AuthorizerType),
|
||||
cel.Variable(RequestResourceAuthorizerVarName, library.ResourceCheckType))
|
||||
}
|
||||
envOpts = append(envOpts,
|
||||
cel.Variable(ObjectVarName, cel.DynType),
|
||||
cel.Variable(OldObjectVarName, cel.DynType),
|
||||
cel.Variable(NamespaceVarName, namespaceType.CelType()),
|
||||
cel.Variable(RequestVarName, requestType.CelType()))
|
||||
|
||||
extended, err := baseEnv.Extend(
|
||||
environment.VersionedOptions{
|
||||
// Feature epoch was actually 1.26, but we artificially set it to 1.0 because these
|
||||
// options should always be present.
|
||||
IntroducedVersion: version.MajorMinor(1, 0),
|
||||
EnvOptions: envOpts,
|
||||
DeclTypes: []*apiservercel.DeclType{
|
||||
namespaceType,
|
||||
requestType,
|
||||
},
|
||||
},
|
||||
)
|
||||
decl := OptionalVariableDeclarations{HasParams: hasParams, HasAuthorizer: hasAuthorizer, StrictCost: strictCost}
|
||||
envs[decl], err = createEnvForOpts(baseEnv, namespaceType, requestType, decl)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("environment misconfigured: %v", err))
|
||||
panic(err)
|
||||
}
|
||||
if strictCost {
|
||||
extended, err = extended.Extend(environment.StrictCostOpt)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("environment misconfigured: %v", err))
|
||||
}
|
||||
}
|
||||
envs[OptionalVariableDeclarations{HasParams: hasParams, HasAuthorizer: hasAuthorizer, StrictCost: strictCost}] = extended
|
||||
}
|
||||
// We only need this ObjectTypes where strict cost is true
|
||||
decl := OptionalVariableDeclarations{HasParams: hasParams, HasAuthorizer: hasAuthorizer, StrictCost: true, HasPatchTypes: true}
|
||||
envs[decl], err = createEnvForOpts(baseEnv, namespaceType, requestType, decl)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return envs
|
||||
}
|
||||
|
||||
func createEnvForOpts(baseEnv *environment.EnvSet, namespaceType *apiservercel.DeclType, requestType *apiservercel.DeclType, opts OptionalVariableDeclarations) (*environment.EnvSet, error) {
|
||||
var envOpts []cel.EnvOption
|
||||
envOpts = append(envOpts,
|
||||
cel.Variable(ObjectVarName, cel.DynType),
|
||||
cel.Variable(OldObjectVarName, cel.DynType),
|
||||
cel.Variable(NamespaceVarName, namespaceType.CelType()),
|
||||
cel.Variable(RequestVarName, requestType.CelType()))
|
||||
if opts.HasParams {
|
||||
envOpts = append(envOpts, cel.Variable(ParamsVarName, cel.DynType))
|
||||
}
|
||||
if opts.HasAuthorizer {
|
||||
envOpts = append(envOpts,
|
||||
cel.Variable(AuthorizerVarName, library.AuthorizerType),
|
||||
cel.Variable(RequestResourceAuthorizerVarName, library.ResourceCheckType))
|
||||
}
|
||||
|
||||
extended, err := baseEnv.Extend(
|
||||
environment.VersionedOptions{
|
||||
// Feature epoch was actually 1.26, but we artificially set it to 1.0 because these
|
||||
// options should always be present.
|
||||
IntroducedVersion: version.MajorMinor(1, 0),
|
||||
EnvOptions: envOpts,
|
||||
DeclTypes: []*apiservercel.DeclType{
|
||||
namespaceType,
|
||||
requestType,
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("environment misconfigured: %w", err)
|
||||
}
|
||||
if opts.StrictCost {
|
||||
extended, err = extended.Extend(environment.StrictCostOpt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("environment misconfigured: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if opts.HasPatchTypes {
|
||||
extended, err = extended.Extend(hasPatchTypes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("environment misconfigured: %w", err)
|
||||
}
|
||||
}
|
||||
return extended, nil
|
||||
}
|
||||
|
||||
var hasPatchTypes = environment.VersionedOptions{
|
||||
// Feature epoch was actually 1.32, but we artificially set it to 1.0 because these
|
||||
// options should always be present.
|
||||
IntroducedVersion: version.MajorMinor(1, 0),
|
||||
EnvOptions: []cel.EnvOption{
|
||||
common.ResolverEnvOption(&mutation.DynamicTypeResolver{}),
|
||||
environment.UnversionedLib(library.JSONPatch), // for jsonPatch.escape() function
|
||||
},
|
||||
}
|
||||
|
51
vendor/k8s.io/apiserver/pkg/admission/plugin/cel/composition.go
generated
vendored
51
vendor/k8s.io/apiserver/pkg/admission/plugin/cel/composition.go
generated
vendored
@ -36,15 +36,27 @@ import (
|
||||
|
||||
const VariablesTypeName = "kubernetes.variables"
|
||||
|
||||
// CompositedCompiler compiles expressions with variable composition.
|
||||
type CompositedCompiler struct {
|
||||
Compiler
|
||||
FilterCompiler
|
||||
ConditionCompiler
|
||||
MutatingCompiler
|
||||
|
||||
CompositionEnv *CompositionEnv
|
||||
}
|
||||
|
||||
type CompositedFilter struct {
|
||||
Filter
|
||||
// CompositedConditionEvaluator provides evaluation of a condition expression with variable composition.
|
||||
// The expressions must return a boolean.
|
||||
type CompositedConditionEvaluator struct {
|
||||
ConditionEvaluator
|
||||
|
||||
compositionEnv *CompositionEnv
|
||||
}
|
||||
|
||||
// CompositedEvaluator provides evaluation of a single expression with variable composition.
|
||||
// The types that may returned by the expression is determined at compilation time.
|
||||
type CompositedEvaluator struct {
|
||||
MutatingEvaluator
|
||||
|
||||
compositionEnv *CompositionEnv
|
||||
}
|
||||
@ -64,11 +76,13 @@ func NewCompositedCompilerFromTemplate(context *CompositionEnv) *CompositedCompi
|
||||
CompiledVariables: map[string]CompilationResult{},
|
||||
}
|
||||
compiler := NewCompiler(context.EnvSet)
|
||||
filterCompiler := NewFilterCompiler(context.EnvSet)
|
||||
conditionCompiler := &conditionCompiler{compiler}
|
||||
mutation := &mutatingCompiler{compiler}
|
||||
return &CompositedCompiler{
|
||||
Compiler: compiler,
|
||||
FilterCompiler: filterCompiler,
|
||||
CompositionEnv: context,
|
||||
Compiler: compiler,
|
||||
ConditionCompiler: conditionCompiler,
|
||||
MutatingCompiler: mutation,
|
||||
CompositionEnv: context,
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,11 +99,20 @@ func (c *CompositedCompiler) CompileAndStoreVariable(variable NamedExpressionAcc
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *CompositedCompiler) Compile(expressions []ExpressionAccessor, optionalDecls OptionalVariableDeclarations, envType environment.Type) Filter {
|
||||
filter := c.FilterCompiler.Compile(expressions, optionalDecls, envType)
|
||||
return &CompositedFilter{
|
||||
Filter: filter,
|
||||
compositionEnv: c.CompositionEnv,
|
||||
func (c *CompositedCompiler) CompileCondition(expressions []ExpressionAccessor, optionalDecls OptionalVariableDeclarations, envType environment.Type) ConditionEvaluator {
|
||||
condition := c.ConditionCompiler.CompileCondition(expressions, optionalDecls, envType)
|
||||
return &CompositedConditionEvaluator{
|
||||
ConditionEvaluator: condition,
|
||||
compositionEnv: c.CompositionEnv,
|
||||
}
|
||||
}
|
||||
|
||||
// CompileEvaluator compiles an mutatingEvaluator for the given expression, options and environment.
|
||||
func (c *CompositedCompiler) CompileMutatingEvaluator(expression ExpressionAccessor, optionalDecls OptionalVariableDeclarations, envType environment.Type) MutatingEvaluator {
|
||||
mutation := c.MutatingCompiler.CompileMutatingEvaluator(expression, optionalDecls, envType)
|
||||
return &CompositedEvaluator{
|
||||
MutatingEvaluator: mutation,
|
||||
compositionEnv: c.CompositionEnv,
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,9 +183,9 @@ func (c *compositionContext) Variables(activation any) ref.Val {
|
||||
return lazyMap
|
||||
}
|
||||
|
||||
func (f *CompositedFilter) ForInput(ctx context.Context, versionedAttr *admission.VersionedAttributes, request *v1.AdmissionRequest, optionalVars OptionalVariableBindings, namespace *corev1.Namespace, runtimeCELCostBudget int64) ([]EvaluationResult, int64, error) {
|
||||
func (f *CompositedConditionEvaluator) ForInput(ctx context.Context, versionedAttr *admission.VersionedAttributes, request *v1.AdmissionRequest, optionalVars OptionalVariableBindings, namespace *corev1.Namespace, runtimeCELCostBudget int64) ([]EvaluationResult, int64, error) {
|
||||
ctx = f.compositionEnv.CreateContext(ctx)
|
||||
return f.Filter.ForInput(ctx, versionedAttr, request, optionalVars, namespace, runtimeCELCostBudget)
|
||||
return f.ConditionEvaluator.ForInput(ctx, versionedAttr, request, optionalVars, namespace, runtimeCELCostBudget)
|
||||
}
|
||||
|
||||
func (c *compositionContext) reportCost(cost int64) {
|
||||
|
216
vendor/k8s.io/apiserver/pkg/admission/plugin/cel/condition.go
generated
vendored
Normal file
216
vendor/k8s.io/apiserver/pkg/admission/plugin/cel/condition.go
generated
vendored
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
Copyright 2022 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 cel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
authenticationv1 "k8s.io/api/authentication/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/cel/environment"
|
||||
)
|
||||
|
||||
// conditionCompiler implement the interface ConditionCompiler.
|
||||
type conditionCompiler struct {
|
||||
compiler Compiler
|
||||
}
|
||||
|
||||
func NewConditionCompiler(env *environment.EnvSet) ConditionCompiler {
|
||||
return &conditionCompiler{compiler: NewCompiler(env)}
|
||||
}
|
||||
|
||||
// CompileCondition compiles the cel expressions defined in the ExpressionAccessors into a ConditionEvaluator
|
||||
func (c *conditionCompiler) CompileCondition(expressionAccessors []ExpressionAccessor, options OptionalVariableDeclarations, mode environment.Type) ConditionEvaluator {
|
||||
compilationResults := make([]CompilationResult, len(expressionAccessors))
|
||||
for i, expressionAccessor := range expressionAccessors {
|
||||
if expressionAccessor == nil {
|
||||
continue
|
||||
}
|
||||
compilationResults[i] = c.compiler.CompileCELExpression(expressionAccessor, options, mode)
|
||||
}
|
||||
return NewCondition(compilationResults)
|
||||
}
|
||||
|
||||
// condition implements the ConditionEvaluator interface
|
||||
type condition struct {
|
||||
compilationResults []CompilationResult
|
||||
}
|
||||
|
||||
func NewCondition(compilationResults []CompilationResult) ConditionEvaluator {
|
||||
return &condition{
|
||||
compilationResults,
|
||||
}
|
||||
}
|
||||
|
||||
func convertObjectToUnstructured(obj interface{}) (*unstructured.Unstructured, error) {
|
||||
if obj == nil || reflect.ValueOf(obj).IsNil() {
|
||||
return &unstructured.Unstructured{Object: nil}, nil
|
||||
}
|
||||
ret, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &unstructured.Unstructured{Object: ret}, nil
|
||||
}
|
||||
|
||||
func objectToResolveVal(r runtime.Object) (interface{}, error) {
|
||||
if r == nil || reflect.ValueOf(r).IsNil() {
|
||||
return nil, nil
|
||||
}
|
||||
v, err := convertObjectToUnstructured(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v.Object, nil
|
||||
}
|
||||
|
||||
// ForInput evaluates the compiled CEL expressions converting them into CELEvaluations
|
||||
// errors per evaluation are returned on the Evaluation object
|
||||
// runtimeCELCostBudget was added for testing purpose only. Callers should always use const RuntimeCELCostBudget from k8s.io/apiserver/pkg/apis/cel/config.go as input.
|
||||
func (c *condition) ForInput(ctx context.Context, versionedAttr *admission.VersionedAttributes, request *admissionv1.AdmissionRequest, inputs OptionalVariableBindings, namespace *v1.Namespace, runtimeCELCostBudget int64) ([]EvaluationResult, int64, error) {
|
||||
// TODO: replace unstructured with ref.Val for CEL variables when native type support is available
|
||||
evaluations := make([]EvaluationResult, len(c.compilationResults))
|
||||
var err error
|
||||
|
||||
// if this activation supports composition, we will need the compositionCtx. It may be nil.
|
||||
compositionCtx, _ := ctx.(CompositionContext)
|
||||
|
||||
activation, err := newActivation(compositionCtx, versionedAttr, request, inputs, namespace)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
|
||||
remainingBudget := runtimeCELCostBudget
|
||||
for i, compilationResult := range c.compilationResults {
|
||||
evaluations[i], remainingBudget, err = activation.Evaluate(ctx, compositionCtx, compilationResult, remainingBudget)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
}
|
||||
|
||||
return evaluations, remainingBudget, nil
|
||||
}
|
||||
|
||||
// TODO: to reuse https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/request/admissionreview.go#L154
|
||||
func CreateAdmissionRequest(attr admission.Attributes, equivalentGVR metav1.GroupVersionResource, equivalentKind metav1.GroupVersionKind) *admissionv1.AdmissionRequest {
|
||||
// Attempting to use same logic as webhook for constructing resource
|
||||
// GVK, GVR, subresource
|
||||
// Use the GVK, GVR that the matcher decided was equivalent to that of the request
|
||||
// https://github.com/kubernetes/kubernetes/blob/90c362b3430bcbbf8f245fadbcd521dab39f1d7c/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/webhook.go#L182-L210
|
||||
gvk := equivalentKind
|
||||
gvr := equivalentGVR
|
||||
subresource := attr.GetSubresource()
|
||||
|
||||
requestGVK := attr.GetKind()
|
||||
requestGVR := attr.GetResource()
|
||||
requestSubResource := attr.GetSubresource()
|
||||
|
||||
aUserInfo := attr.GetUserInfo()
|
||||
var userInfo authenticationv1.UserInfo
|
||||
if aUserInfo != nil {
|
||||
userInfo = authenticationv1.UserInfo{
|
||||
Extra: make(map[string]authenticationv1.ExtraValue),
|
||||
Groups: aUserInfo.GetGroups(),
|
||||
UID: aUserInfo.GetUID(),
|
||||
Username: aUserInfo.GetName(),
|
||||
}
|
||||
// Convert the extra information in the user object
|
||||
for key, val := range aUserInfo.GetExtra() {
|
||||
userInfo.Extra[key] = authenticationv1.ExtraValue(val)
|
||||
}
|
||||
}
|
||||
|
||||
dryRun := attr.IsDryRun()
|
||||
|
||||
return &admissionv1.AdmissionRequest{
|
||||
Kind: metav1.GroupVersionKind{
|
||||
Group: gvk.Group,
|
||||
Kind: gvk.Kind,
|
||||
Version: gvk.Version,
|
||||
},
|
||||
Resource: metav1.GroupVersionResource{
|
||||
Group: gvr.Group,
|
||||
Resource: gvr.Resource,
|
||||
Version: gvr.Version,
|
||||
},
|
||||
SubResource: subresource,
|
||||
RequestKind: &metav1.GroupVersionKind{
|
||||
Group: requestGVK.Group,
|
||||
Kind: requestGVK.Kind,
|
||||
Version: requestGVK.Version,
|
||||
},
|
||||
RequestResource: &metav1.GroupVersionResource{
|
||||
Group: requestGVR.Group,
|
||||
Resource: requestGVR.Resource,
|
||||
Version: requestGVR.Version,
|
||||
},
|
||||
RequestSubResource: requestSubResource,
|
||||
Name: attr.GetName(),
|
||||
Namespace: attr.GetNamespace(),
|
||||
Operation: admissionv1.Operation(attr.GetOperation()),
|
||||
UserInfo: userInfo,
|
||||
// Leave Object and OldObject unset since we don't provide access to them via request
|
||||
DryRun: &dryRun,
|
||||
Options: runtime.RawExtension{
|
||||
Object: attr.GetOperationOptions(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CreateNamespaceObject creates a Namespace object that is suitable for the CEL evaluation.
|
||||
// If the namespace is nil, CreateNamespaceObject returns nil
|
||||
func CreateNamespaceObject(namespace *v1.Namespace) *v1.Namespace {
|
||||
if namespace == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &v1.Namespace{
|
||||
Status: namespace.Status,
|
||||
Spec: namespace.Spec,
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespace.Name,
|
||||
GenerateName: namespace.GenerateName,
|
||||
Namespace: namespace.Namespace,
|
||||
UID: namespace.UID,
|
||||
ResourceVersion: namespace.ResourceVersion,
|
||||
Generation: namespace.Generation,
|
||||
CreationTimestamp: namespace.CreationTimestamp,
|
||||
DeletionTimestamp: namespace.DeletionTimestamp,
|
||||
DeletionGracePeriodSeconds: namespace.DeletionGracePeriodSeconds,
|
||||
Labels: namespace.Labels,
|
||||
Annotations: namespace.Annotations,
|
||||
Finalizers: namespace.Finalizers,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CompilationErrors returns a list of all the errors from the compilation of the mutatingEvaluator
|
||||
func (c *condition) CompilationErrors() []error {
|
||||
compilationErrors := []error{}
|
||||
for _, result := range c.compilationResults {
|
||||
if result.Error != nil {
|
||||
compilationErrors = append(compilationErrors, result.Error)
|
||||
}
|
||||
}
|
||||
return compilationErrors
|
||||
}
|
361
vendor/k8s.io/apiserver/pkg/admission/plugin/cel/filter.go
generated
vendored
361
vendor/k8s.io/apiserver/pkg/admission/plugin/cel/filter.go
generated
vendored
@ -1,361 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 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 cel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/google/cel-go/interpreter"
|
||||
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
authenticationv1 "k8s.io/api/authentication/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/cel"
|
||||
"k8s.io/apiserver/pkg/cel/environment"
|
||||
"k8s.io/apiserver/pkg/cel/library"
|
||||
)
|
||||
|
||||
// filterCompiler implement the interface FilterCompiler.
|
||||
type filterCompiler struct {
|
||||
compiler Compiler
|
||||
}
|
||||
|
||||
func NewFilterCompiler(env *environment.EnvSet) FilterCompiler {
|
||||
return &filterCompiler{compiler: NewCompiler(env)}
|
||||
}
|
||||
|
||||
type evaluationActivation struct {
|
||||
object, oldObject, params, request, namespace, authorizer, requestResourceAuthorizer, variables interface{}
|
||||
}
|
||||
|
||||
// ResolveName returns a value from the activation by qualified name, or false if the name
|
||||
// could not be found.
|
||||
func (a *evaluationActivation) ResolveName(name string) (interface{}, bool) {
|
||||
switch name {
|
||||
case ObjectVarName:
|
||||
return a.object, true
|
||||
case OldObjectVarName:
|
||||
return a.oldObject, true
|
||||
case ParamsVarName:
|
||||
return a.params, true // params may be null
|
||||
case RequestVarName:
|
||||
return a.request, true
|
||||
case NamespaceVarName:
|
||||
return a.namespace, true
|
||||
case AuthorizerVarName:
|
||||
return a.authorizer, a.authorizer != nil
|
||||
case RequestResourceAuthorizerVarName:
|
||||
return a.requestResourceAuthorizer, a.requestResourceAuthorizer != nil
|
||||
case VariableVarName: // variables always present
|
||||
return a.variables, true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
// Parent returns the parent of the current activation, may be nil.
|
||||
// If non-nil, the parent will be searched during resolve calls.
|
||||
func (a *evaluationActivation) Parent() interpreter.Activation {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Compile compiles the cel expressions defined in the ExpressionAccessors into a Filter
|
||||
func (c *filterCompiler) Compile(expressionAccessors []ExpressionAccessor, options OptionalVariableDeclarations, mode environment.Type) Filter {
|
||||
compilationResults := make([]CompilationResult, len(expressionAccessors))
|
||||
for i, expressionAccessor := range expressionAccessors {
|
||||
if expressionAccessor == nil {
|
||||
continue
|
||||
}
|
||||
compilationResults[i] = c.compiler.CompileCELExpression(expressionAccessor, options, mode)
|
||||
}
|
||||
return NewFilter(compilationResults)
|
||||
}
|
||||
|
||||
// filter implements the Filter interface
|
||||
type filter struct {
|
||||
compilationResults []CompilationResult
|
||||
}
|
||||
|
||||
func NewFilter(compilationResults []CompilationResult) Filter {
|
||||
return &filter{
|
||||
compilationResults,
|
||||
}
|
||||
}
|
||||
|
||||
func convertObjectToUnstructured(obj interface{}) (*unstructured.Unstructured, error) {
|
||||
if obj == nil || reflect.ValueOf(obj).IsNil() {
|
||||
return &unstructured.Unstructured{Object: nil}, nil
|
||||
}
|
||||
ret, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &unstructured.Unstructured{Object: ret}, nil
|
||||
}
|
||||
|
||||
func objectToResolveVal(r runtime.Object) (interface{}, error) {
|
||||
if r == nil || reflect.ValueOf(r).IsNil() {
|
||||
return nil, nil
|
||||
}
|
||||
v, err := convertObjectToUnstructured(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v.Object, nil
|
||||
}
|
||||
|
||||
// ForInput evaluates the compiled CEL expressions converting them into CELEvaluations
|
||||
// errors per evaluation are returned on the Evaluation object
|
||||
// runtimeCELCostBudget was added for testing purpose only. Callers should always use const RuntimeCELCostBudget from k8s.io/apiserver/pkg/apis/cel/config.go as input.
|
||||
func (f *filter) ForInput(ctx context.Context, versionedAttr *admission.VersionedAttributes, request *admissionv1.AdmissionRequest, inputs OptionalVariableBindings, namespace *v1.Namespace, runtimeCELCostBudget int64) ([]EvaluationResult, int64, error) {
|
||||
// TODO: replace unstructured with ref.Val for CEL variables when native type support is available
|
||||
evaluations := make([]EvaluationResult, len(f.compilationResults))
|
||||
var err error
|
||||
|
||||
oldObjectVal, err := objectToResolveVal(versionedAttr.VersionedOldObject)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
objectVal, err := objectToResolveVal(versionedAttr.VersionedObject)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
var paramsVal, authorizerVal, requestResourceAuthorizerVal any
|
||||
if inputs.VersionedParams != nil {
|
||||
paramsVal, err = objectToResolveVal(inputs.VersionedParams)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
}
|
||||
|
||||
if inputs.Authorizer != nil {
|
||||
authorizerVal = library.NewAuthorizerVal(versionedAttr.GetUserInfo(), inputs.Authorizer)
|
||||
requestResourceAuthorizerVal = library.NewResourceAuthorizerVal(versionedAttr.GetUserInfo(), inputs.Authorizer, versionedAttr)
|
||||
}
|
||||
|
||||
requestVal, err := convertObjectToUnstructured(request)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
namespaceVal, err := objectToResolveVal(namespace)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
va := &evaluationActivation{
|
||||
object: objectVal,
|
||||
oldObject: oldObjectVal,
|
||||
params: paramsVal,
|
||||
request: requestVal.Object,
|
||||
namespace: namespaceVal,
|
||||
authorizer: authorizerVal,
|
||||
requestResourceAuthorizer: requestResourceAuthorizerVal,
|
||||
}
|
||||
|
||||
// composition is an optional feature that only applies for ValidatingAdmissionPolicy.
|
||||
// check if the context allows composition
|
||||
var compositionCtx CompositionContext
|
||||
var ok bool
|
||||
if compositionCtx, ok = ctx.(CompositionContext); ok {
|
||||
va.variables = compositionCtx.Variables(va)
|
||||
}
|
||||
|
||||
remainingBudget := runtimeCELCostBudget
|
||||
for i, compilationResult := range f.compilationResults {
|
||||
var evaluation = &evaluations[i]
|
||||
if compilationResult.ExpressionAccessor == nil { // in case of placeholder
|
||||
continue
|
||||
}
|
||||
evaluation.ExpressionAccessor = compilationResult.ExpressionAccessor
|
||||
if compilationResult.Error != nil {
|
||||
evaluation.Error = &cel.Error{
|
||||
Type: cel.ErrorTypeInvalid,
|
||||
Detail: fmt.Sprintf("compilation error: %v", compilationResult.Error),
|
||||
Cause: compilationResult.Error,
|
||||
}
|
||||
continue
|
||||
}
|
||||
if compilationResult.Program == nil {
|
||||
evaluation.Error = &cel.Error{
|
||||
Type: cel.ErrorTypeInternal,
|
||||
Detail: fmt.Sprintf("unexpected internal error compiling expression"),
|
||||
}
|
||||
continue
|
||||
}
|
||||
t1 := time.Now()
|
||||
evalResult, evalDetails, err := compilationResult.Program.ContextEval(ctx, va)
|
||||
// budget may be spent due to lazy evaluation of composited variables
|
||||
if compositionCtx != nil {
|
||||
compositionCost := compositionCtx.GetAndResetCost()
|
||||
if compositionCost > remainingBudget {
|
||||
return nil, -1, &cel.Error{
|
||||
Type: cel.ErrorTypeInvalid,
|
||||
Detail: fmt.Sprintf("validation failed due to running out of cost budget, no further validation rules will be run"),
|
||||
Cause: cel.ErrOutOfBudget,
|
||||
}
|
||||
}
|
||||
remainingBudget -= compositionCost
|
||||
}
|
||||
elapsed := time.Since(t1)
|
||||
evaluation.Elapsed = elapsed
|
||||
if evalDetails == nil {
|
||||
return nil, -1, &cel.Error{
|
||||
Type: cel.ErrorTypeInternal,
|
||||
Detail: fmt.Sprintf("runtime cost could not be calculated for expression: %v, no further expression will be run", compilationResult.ExpressionAccessor.GetExpression()),
|
||||
}
|
||||
} else {
|
||||
rtCost := evalDetails.ActualCost()
|
||||
if rtCost == nil {
|
||||
return nil, -1, &cel.Error{
|
||||
Type: cel.ErrorTypeInvalid,
|
||||
Detail: fmt.Sprintf("runtime cost could not be calculated for expression: %v, no further expression will be run", compilationResult.ExpressionAccessor.GetExpression()),
|
||||
Cause: cel.ErrOutOfBudget,
|
||||
}
|
||||
} else {
|
||||
if *rtCost > math.MaxInt64 || int64(*rtCost) > remainingBudget {
|
||||
return nil, -1, &cel.Error{
|
||||
Type: cel.ErrorTypeInvalid,
|
||||
Detail: fmt.Sprintf("validation failed due to running out of cost budget, no further validation rules will be run"),
|
||||
Cause: cel.ErrOutOfBudget,
|
||||
}
|
||||
}
|
||||
remainingBudget -= int64(*rtCost)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
evaluation.Error = &cel.Error{
|
||||
Type: cel.ErrorTypeInvalid,
|
||||
Detail: fmt.Sprintf("expression '%v' resulted in error: %v", compilationResult.ExpressionAccessor.GetExpression(), err),
|
||||
}
|
||||
} else {
|
||||
evaluation.EvalResult = evalResult
|
||||
}
|
||||
}
|
||||
|
||||
return evaluations, remainingBudget, nil
|
||||
}
|
||||
|
||||
// TODO: to reuse https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/request/admissionreview.go#L154
|
||||
func CreateAdmissionRequest(attr admission.Attributes, equivalentGVR metav1.GroupVersionResource, equivalentKind metav1.GroupVersionKind) *admissionv1.AdmissionRequest {
|
||||
// Attempting to use same logic as webhook for constructing resource
|
||||
// GVK, GVR, subresource
|
||||
// Use the GVK, GVR that the matcher decided was equivalent to that of the request
|
||||
// https://github.com/kubernetes/kubernetes/blob/90c362b3430bcbbf8f245fadbcd521dab39f1d7c/staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/generic/webhook.go#L182-L210
|
||||
gvk := equivalentKind
|
||||
gvr := equivalentGVR
|
||||
subresource := attr.GetSubresource()
|
||||
|
||||
requestGVK := attr.GetKind()
|
||||
requestGVR := attr.GetResource()
|
||||
requestSubResource := attr.GetSubresource()
|
||||
|
||||
aUserInfo := attr.GetUserInfo()
|
||||
var userInfo authenticationv1.UserInfo
|
||||
if aUserInfo != nil {
|
||||
userInfo = authenticationv1.UserInfo{
|
||||
Extra: make(map[string]authenticationv1.ExtraValue),
|
||||
Groups: aUserInfo.GetGroups(),
|
||||
UID: aUserInfo.GetUID(),
|
||||
Username: aUserInfo.GetName(),
|
||||
}
|
||||
// Convert the extra information in the user object
|
||||
for key, val := range aUserInfo.GetExtra() {
|
||||
userInfo.Extra[key] = authenticationv1.ExtraValue(val)
|
||||
}
|
||||
}
|
||||
|
||||
dryRun := attr.IsDryRun()
|
||||
|
||||
return &admissionv1.AdmissionRequest{
|
||||
Kind: metav1.GroupVersionKind{
|
||||
Group: gvk.Group,
|
||||
Kind: gvk.Kind,
|
||||
Version: gvk.Version,
|
||||
},
|
||||
Resource: metav1.GroupVersionResource{
|
||||
Group: gvr.Group,
|
||||
Resource: gvr.Resource,
|
||||
Version: gvr.Version,
|
||||
},
|
||||
SubResource: subresource,
|
||||
RequestKind: &metav1.GroupVersionKind{
|
||||
Group: requestGVK.Group,
|
||||
Kind: requestGVK.Kind,
|
||||
Version: requestGVK.Version,
|
||||
},
|
||||
RequestResource: &metav1.GroupVersionResource{
|
||||
Group: requestGVR.Group,
|
||||
Resource: requestGVR.Resource,
|
||||
Version: requestGVR.Version,
|
||||
},
|
||||
RequestSubResource: requestSubResource,
|
||||
Name: attr.GetName(),
|
||||
Namespace: attr.GetNamespace(),
|
||||
Operation: admissionv1.Operation(attr.GetOperation()),
|
||||
UserInfo: userInfo,
|
||||
// Leave Object and OldObject unset since we don't provide access to them via request
|
||||
DryRun: &dryRun,
|
||||
Options: runtime.RawExtension{
|
||||
Object: attr.GetOperationOptions(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CreateNamespaceObject creates a Namespace object that is suitable for the CEL evaluation.
|
||||
// If the namespace is nil, CreateNamespaceObject returns nil
|
||||
func CreateNamespaceObject(namespace *v1.Namespace) *v1.Namespace {
|
||||
if namespace == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &v1.Namespace{
|
||||
Status: namespace.Status,
|
||||
Spec: namespace.Spec,
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespace.Name,
|
||||
GenerateName: namespace.GenerateName,
|
||||
Namespace: namespace.Namespace,
|
||||
UID: namespace.UID,
|
||||
ResourceVersion: namespace.ResourceVersion,
|
||||
Generation: namespace.Generation,
|
||||
CreationTimestamp: namespace.CreationTimestamp,
|
||||
DeletionTimestamp: namespace.DeletionTimestamp,
|
||||
DeletionGracePeriodSeconds: namespace.DeletionGracePeriodSeconds,
|
||||
Labels: namespace.Labels,
|
||||
Annotations: namespace.Annotations,
|
||||
Finalizers: namespace.Finalizers,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CompilationErrors returns a list of all the errors from the compilation of the evaluator
|
||||
func (e *filter) CompilationErrors() []error {
|
||||
compilationErrors := []error{}
|
||||
for _, result := range e.compilationResults {
|
||||
if result.Error != nil {
|
||||
compilationErrors = append(compilationErrors, result.Error)
|
||||
}
|
||||
}
|
||||
return compilationErrors
|
||||
}
|
41
vendor/k8s.io/apiserver/pkg/admission/plugin/cel/interface.go
generated
vendored
41
vendor/k8s.io/apiserver/pkg/admission/plugin/cel/interface.go
generated
vendored
@ -63,12 +63,15 @@ type OptionalVariableDeclarations struct {
|
||||
HasAuthorizer bool
|
||||
// StrictCost specifies if the CEL cost limitation is strict for extended libraries as well as native libraries.
|
||||
StrictCost bool
|
||||
// HasPatchTypes specifies if JSONPatch, Object, Object.metadata and similar types are available in CEL. These can be used
|
||||
// to initialize the typed objects in CEL required to create patches.
|
||||
HasPatchTypes bool
|
||||
}
|
||||
|
||||
// FilterCompiler contains a function to assist with converting types and values to/from CEL-typed values.
|
||||
type FilterCompiler interface {
|
||||
// Compile is used for the cel expression compilation
|
||||
Compile(expressions []ExpressionAccessor, optionalDecls OptionalVariableDeclarations, envType environment.Type) Filter
|
||||
// ConditionCompiler contains a function to assist with converting types and values to/from CEL-typed values.
|
||||
type ConditionCompiler interface {
|
||||
// CompileCondition is used for the cel expression compilation
|
||||
CompileCondition(expressions []ExpressionAccessor, optionalDecls OptionalVariableDeclarations, envType environment.Type) ConditionEvaluator
|
||||
}
|
||||
|
||||
// OptionalVariableBindings provides expression bindings for optional CEL variables.
|
||||
@ -82,16 +85,38 @@ type OptionalVariableBindings struct {
|
||||
Authorizer authorizer.Authorizer
|
||||
}
|
||||
|
||||
// Filter contains a function to evaluate compiled CEL-typed values
|
||||
// ConditionEvaluator contains the result of compiling a CEL expression
|
||||
// that evaluates to a condition. This is used both for validation and pre-conditions.
|
||||
// It expects the inbound object to already have been converted to the version expected
|
||||
// by the underlying CEL code (which is indicated by the match criteria of a policy definition).
|
||||
// versionedParams may be nil.
|
||||
type Filter interface {
|
||||
type ConditionEvaluator interface {
|
||||
// ForInput converts compiled CEL-typed values into evaluated CEL-typed value.
|
||||
// runtimeCELCostBudget was added for testing purpose only. Callers should always use const RuntimeCELCostBudget from k8s.io/apiserver/pkg/apis/cel/config.go as input.
|
||||
// If cost budget is calculated, the filter should return the remaining budget.
|
||||
// If cost budget is calculated, the condition should return the remaining budget.
|
||||
ForInput(ctx context.Context, versionedAttr *admission.VersionedAttributes, request *v1.AdmissionRequest, optionalVars OptionalVariableBindings, namespace *corev1.Namespace, runtimeCELCostBudget int64) ([]EvaluationResult, int64, error)
|
||||
|
||||
// CompilationErrors returns a list of errors from the compilation of the evaluator
|
||||
// CompilationErrors returns a list of errors from the compilation of the mutatingEvaluator
|
||||
CompilationErrors() []error
|
||||
}
|
||||
|
||||
// MutatingCompiler contains a function to assist with converting types and values to/from CEL-typed values.
|
||||
type MutatingCompiler interface {
|
||||
// CompileMutatingEvaluator is used for the cel expression compilation
|
||||
CompileMutatingEvaluator(expression ExpressionAccessor, optionalDecls OptionalVariableDeclarations, envType environment.Type) MutatingEvaluator
|
||||
}
|
||||
|
||||
// MutatingEvaluator contains the result of compiling a CEL expression
|
||||
// that evaluates to a mutation.
|
||||
// It expects the inbound object to already have been converted to the version expected
|
||||
// by the underlying CEL code (which is indicated by the match criteria of a policy definition).
|
||||
// versionedParams may be nil.
|
||||
type MutatingEvaluator interface {
|
||||
// ForInput converts compiled CEL-typed values into a CEL-typed value representing a mutation.
|
||||
// runtimeCELCostBudget was added for testing purpose only. Callers should always use const RuntimeCELCostBudget from k8s.io/apiserver/pkg/apis/cel/config.go as input.
|
||||
// If cost budget is calculated, the condition should return the remaining budget.
|
||||
ForInput(ctx context.Context, versionedAttr *admission.VersionedAttributes, request *v1.AdmissionRequest, optionalVars OptionalVariableBindings, namespace *corev1.Namespace, runtimeCELCostBudget int64) (EvaluationResult, int64, error)
|
||||
|
||||
// CompilationErrors returns a list of errors from the compilation of the mutatingEvaluator
|
||||
CompilationErrors() []error
|
||||
}
|
||||
|
73
vendor/k8s.io/apiserver/pkg/admission/plugin/cel/mutation.go
generated
vendored
Normal file
73
vendor/k8s.io/apiserver/pkg/admission/plugin/cel/mutation.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright 2024 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 cel
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/cel/environment"
|
||||
)
|
||||
|
||||
// mutatingCompiler provides a MutatingCompiler implementation.
|
||||
type mutatingCompiler struct {
|
||||
compiler Compiler
|
||||
}
|
||||
|
||||
// CompileMutatingEvaluator compiles a CEL expression for admission plugins and returns an MutatingEvaluator for executing the
|
||||
// compiled CEL expression.
|
||||
func (p *mutatingCompiler) CompileMutatingEvaluator(expressionAccessor ExpressionAccessor, options OptionalVariableDeclarations, mode environment.Type) MutatingEvaluator {
|
||||
compilationResult := p.compiler.CompileCELExpression(expressionAccessor, options, mode)
|
||||
return NewMutatingEvaluator(compilationResult)
|
||||
}
|
||||
|
||||
type mutatingEvaluator struct {
|
||||
compilationResult CompilationResult
|
||||
}
|
||||
|
||||
func NewMutatingEvaluator(compilationResult CompilationResult) MutatingEvaluator {
|
||||
return &mutatingEvaluator{compilationResult}
|
||||
}
|
||||
|
||||
// ForInput evaluates the compiled CEL expression and returns an evaluation result
|
||||
// errors per evaluation are returned in the evaluation result
|
||||
// runtimeCELCostBudget was added for testing purpose only. Callers should always use const RuntimeCELCostBudget from k8s.io/apiserver/pkg/apis/cel/config.go as input.
|
||||
func (p *mutatingEvaluator) ForInput(ctx context.Context, versionedAttr *admission.VersionedAttributes, request *admissionv1.AdmissionRequest, inputs OptionalVariableBindings, namespace *v1.Namespace, runtimeCELCostBudget int64) (EvaluationResult, int64, error) {
|
||||
// if this activation supports composition, we will need the compositionCtx. It may be nil.
|
||||
compositionCtx, _ := ctx.(CompositionContext)
|
||||
|
||||
activation, err := newActivation(compositionCtx, versionedAttr, request, inputs, namespace)
|
||||
if err != nil {
|
||||
return EvaluationResult{}, -1, err
|
||||
}
|
||||
evaluation, remainingBudget, err := activation.Evaluate(ctx, compositionCtx, p.compilationResult, runtimeCELCostBudget)
|
||||
if err != nil {
|
||||
return evaluation, -1, err
|
||||
}
|
||||
return evaluation, remainingBudget, nil
|
||||
|
||||
}
|
||||
|
||||
// CompilationErrors returns a list of all the errors from the compilation of the mutatingEvaluator
|
||||
func (p *mutatingEvaluator) CompilationErrors() (compilationErrors []error) {
|
||||
if p.compilationResult.Error != nil {
|
||||
return []error{p.compilationResult.Error}
|
||||
}
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user