mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-20 18:31:15 +00:00
Merge pull request #113758 from alexzielenski/readyFunc-refactor
use admission.Handler readyFunc for CEL Admission plugin
This commit is contained in:
commit
aeb8a8dfa4
@ -21,17 +21,16 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apiserver/pkg/features"
|
"k8s.io/apiserver/pkg/features"
|
||||||
"k8s.io/client-go/dynamic"
|
"k8s.io/client-go/dynamic"
|
||||||
"k8s.io/component-base/featuregate"
|
"k8s.io/component-base/featuregate"
|
||||||
"time"
|
|
||||||
|
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
"k8s.io/apiserver/pkg/admission/initializer"
|
"k8s.io/apiserver/pkg/admission/initializer"
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/tools/cache"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -60,6 +59,7 @@ func Register(plugins *admission.Plugins) {
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
type celAdmissionPlugin struct {
|
type celAdmissionPlugin struct {
|
||||||
|
*admission.Handler
|
||||||
evaluator CELPolicyEvaluator
|
evaluator CELPolicyEvaluator
|
||||||
|
|
||||||
inspectedFeatureGates bool
|
inspectedFeatureGates bool
|
||||||
@ -83,8 +83,9 @@ var _ admission.InitializationValidator = &celAdmissionPlugin{}
|
|||||||
var _ admission.ValidationInterface = &celAdmissionPlugin{}
|
var _ admission.ValidationInterface = &celAdmissionPlugin{}
|
||||||
|
|
||||||
func NewPlugin() (admission.Interface, error) {
|
func NewPlugin() (admission.Interface, error) {
|
||||||
result := &celAdmissionPlugin{}
|
return &celAdmissionPlugin{
|
||||||
return result, nil
|
Handler: admission.NewHandler(admission.Connect, admission.Create, admission.Delete, admission.Update),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *celAdmissionPlugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
|
func (c *celAdmissionPlugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
|
||||||
@ -142,6 +143,7 @@ func (c *celAdmissionPlugin) ValidateInitialization() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.SetReadyFunc(c.evaluator.HasSynced)
|
||||||
go c.evaluator.Run(c.stopCh)
|
go c.evaluator.Run(c.stopCh)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -163,16 +165,13 @@ func (c *celAdmissionPlugin) Validate(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
deadlined, cancel := context.WithTimeout(ctx, 2*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
// isPolicyResource determines if an admission.Attributes object is describing
|
// isPolicyResource determines if an admission.Attributes object is describing
|
||||||
// the admission of a ValidatingAdmissionPolicy or a ValidatingAdmissionPolicyBinding
|
// the admission of a ValidatingAdmissionPolicy or a ValidatingAdmissionPolicyBinding
|
||||||
if isPolicyResource(a) {
|
if isPolicyResource(a) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cache.WaitForNamedCacheSync("cel-admission-plugin", deadlined.Done(), c.evaluator.HasSynced) {
|
if !c.WaitForReady() {
|
||||||
return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request"))
|
return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ func (f *fakeCompiler) RegisterBinding(binding *v1alpha1.ValidatingAdmissionPoli
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setupFakeTest(t *testing.T, comp *fakeCompiler) (plugin admission.ValidationInterface, paramTracker, policyTracker clienttesting.ObjectTracker, controller *celAdmissionController) {
|
func setupFakeTest(t *testing.T, comp *fakeCompiler) (plugin admission.ValidationInterface, paramTracker, policyTracker clienttesting.ObjectTracker, controller *celAdmissionController) {
|
||||||
return setupTestCommon(t, comp)
|
return setupTestCommon(t, comp, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starts CEL admission controller and sets up a plugin configured with it as well
|
// Starts CEL admission controller and sets up a plugin configured with it as well
|
||||||
@ -237,7 +237,9 @@ func setupFakeTest(t *testing.T, comp *fakeCompiler) (plugin admission.Validatio
|
|||||||
// support multiple types of params this function needs to be augmented
|
// support multiple types of params this function needs to be augmented
|
||||||
//
|
//
|
||||||
// PolicyTracker expects FakePolicyDefinition and FakePolicyBinding types
|
// PolicyTracker expects FakePolicyDefinition and FakePolicyBinding types
|
||||||
func setupTestCommon(t *testing.T, compiler ValidatorCompiler) (plugin admission.ValidationInterface, paramTracker, policyTracker clienttesting.ObjectTracker, controller *celAdmissionController) {
|
// !TODO: refactor this test/framework to remove startInformers argument and
|
||||||
|
// clean up the return args, and in general make it more accessible.
|
||||||
|
func setupTestCommon(t *testing.T, compiler ValidatorCompiler, shouldStartInformers bool) (plugin admission.ValidationInterface, paramTracker, policyTracker clienttesting.ObjectTracker, controller *celAdmissionController) {
|
||||||
testContext, testContextCancel := context.WithCancel(context.Background())
|
testContext, testContextCancel := context.WithCancel(context.Background())
|
||||||
t.Cleanup(testContextCancel)
|
t.Cleanup(testContextCancel)
|
||||||
|
|
||||||
@ -259,7 +261,11 @@ func setupTestCommon(t *testing.T, compiler ValidatorCompiler) (plugin admission
|
|||||||
panic("Unexpected error.")
|
panic("Unexpected error.")
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := &celAdmissionPlugin{enabled: true}
|
plug, err := NewPlugin()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
handler := plug.(*celAdmissionPlugin)
|
||||||
|
handler.enabled = true
|
||||||
|
|
||||||
genericInitializer := initializer.New(fakeClient, dynamicClient, fakeInformerFactory, nil, featureGate, testContext.Done())
|
genericInitializer := initializer.New(fakeClient, dynamicClient, fakeInformerFactory, nil, featureGate, testContext.Done())
|
||||||
genericInitializer.Initialize(handler)
|
genericInitializer.Initialize(handler)
|
||||||
@ -272,14 +278,19 @@ func setupTestCommon(t *testing.T, compiler ValidatorCompiler) (plugin admission
|
|||||||
controller = handler.evaluator.(*celAdmissionController)
|
controller = handler.evaluator.(*celAdmissionController)
|
||||||
controller.validatorCompiler = compiler
|
controller.validatorCompiler = compiler
|
||||||
|
|
||||||
// Make sure to start the fake informers
|
|
||||||
fakeInformerFactory.Start(testContext.Done())
|
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
testContextCancel()
|
testContextCancel()
|
||||||
// wait for informer factory to shutdown
|
// wait for informer factory to shutdown
|
||||||
fakeInformerFactory.Shutdown()
|
fakeInformerFactory.Shutdown()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if !shouldStartInformers {
|
||||||
|
return handler, dynamicClient.Tracker(), fakeClient.Tracker(), controller
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure to start the fake informers
|
||||||
|
fakeInformerFactory.Start(testContext.Done())
|
||||||
|
|
||||||
// Wait for admission controller to begin its object watches
|
// Wait for admission controller to begin its object watches
|
||||||
// This is because there is a very rare (0.05% on my machine) race doing the
|
// This is because there is a very rare (0.05% on my machine) race doing the
|
||||||
// initial List+Watch if an object is added after the list, but before the
|
// initial List+Watch if an object is added after the list, but before the
|
||||||
@ -532,6 +543,38 @@ func must3[T any, I any](val T, _ I, err error) T {
|
|||||||
// Functionality Tests
|
// Functionality Tests
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
func TestPluginNotReady(t *testing.T) {
|
||||||
|
compiler := &fakeCompiler{
|
||||||
|
// Match everything by default
|
||||||
|
DefaultMatch: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show that an unstarted informer (or one that has failed its listwatch)
|
||||||
|
// will show proper error from plugin
|
||||||
|
handler, _, _, _ := setupTestCommon(t, compiler, false)
|
||||||
|
err := handler.Validate(
|
||||||
|
context.Background(),
|
||||||
|
// Object is irrelevant/unchecked for this test. Just test that
|
||||||
|
// the evaluator is executed, and returns a denial
|
||||||
|
attributeRecord(nil, fakeParams, admission.Create),
|
||||||
|
&admission.RuntimeObjectInterfaces{},
|
||||||
|
)
|
||||||
|
|
||||||
|
require.ErrorContains(t, err, "not yet ready to handle request")
|
||||||
|
|
||||||
|
// Show that by now starting the informer, the error is dissipated
|
||||||
|
handler, _, _, _ = setupTestCommon(t, compiler, true)
|
||||||
|
err = handler.Validate(
|
||||||
|
context.Background(),
|
||||||
|
// Object is irrelevant/unchecked for this test. Just test that
|
||||||
|
// the evaluator is executed, and returns a denial
|
||||||
|
attributeRecord(nil, fakeParams, admission.Create),
|
||||||
|
&admission.RuntimeObjectInterfaces{},
|
||||||
|
)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestBasicPolicyDefinitionFailure(t *testing.T) {
|
func TestBasicPolicyDefinitionFailure(t *testing.T) {
|
||||||
testContext, testContextCancel := context.WithCancel(context.Background())
|
testContext, testContextCancel := context.WithCancel(context.Background())
|
||||||
defer testContextCancel()
|
defer testContextCancel()
|
||||||
|
Loading…
Reference in New Issue
Block a user