Merge pull request #130595 from tkashem/omit-admission

KEP-3926: skip admission validation for unsafe delete

Kubernetes-commit: 61529d54f22802523e28fd7b6b5d4483d381bfad
This commit is contained in:
Kubernetes Publisher 2025-03-17 09:35:49 -07:00
commit d750e2f2bf
4 changed files with 55 additions and 5 deletions

2
go.mod
View File

@ -50,7 +50,7 @@ require (
gopkg.in/natefinch/lumberjack.v2 v2.2.1
k8s.io/api v0.0.0-20250314173034-c4f583a4a0c0
k8s.io/apimachinery v0.0.0-20250316224947-6ce776c88d38
k8s.io/client-go v0.0.0-20250317173544-97feb5b4e133
k8s.io/client-go v0.0.0-20250317173545-b4e9c912255d
k8s.io/component-base v0.0.0-20250314013811-792166919ea6
k8s.io/klog/v2 v2.130.1
k8s.io/kms v0.0.0-20250308014716-89c23671c056

4
go.sum
View File

@ -371,8 +371,8 @@ k8s.io/api v0.0.0-20250314173034-c4f583a4a0c0 h1:lhmrz3g0hGKYb1C6kbotRXKcRCx/1x2
k8s.io/api v0.0.0-20250314173034-c4f583a4a0c0/go.mod h1:KyMJKlD84N/kjcmc/m15SaydURaQRYKGRGRLsz83opo=
k8s.io/apimachinery v0.0.0-20250316224947-6ce776c88d38 h1:FRtTvD6cz3EPDpIonDNShy6I5sB7LebdSb8/oEj5bkg=
k8s.io/apimachinery v0.0.0-20250316224947-6ce776c88d38/go.mod h1:S2OIkExGqJOXYSYcAJwQ9zWcc6BkBUdTJUu4M7z0cvo=
k8s.io/client-go v0.0.0-20250317173544-97feb5b4e133 h1:yHpcNTxSamIcQi4lJUZDJh2wdVuR45yTPjgjpNA1SlQ=
k8s.io/client-go v0.0.0-20250317173544-97feb5b4e133/go.mod h1:Crv1s2vYOOdElbz/0fFLNhEaLcK48ZXjuUHuwDLBaMo=
k8s.io/client-go v0.0.0-20250317173545-b4e9c912255d h1:vgQ2MiKX4EQCBsPLmKUfNG6USKpp6VqdXtJ+nYcew6Q=
k8s.io/client-go v0.0.0-20250317173545-b4e9c912255d/go.mod h1:Crv1s2vYOOdElbz/0fFLNhEaLcK48ZXjuUHuwDLBaMo=
k8s.io/component-base v0.0.0-20250314013811-792166919ea6 h1:e3uteoFmipq017BqvEGsZMd2NJ70BNG8q9tJqmoAIjw=
k8s.io/component-base v0.0.0-20250314013811-792166919ea6/go.mod h1:fofD+M/PFvgSSrpoHM4YNpml4jKf8cMXogjsQgRnryA=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=

View File

@ -107,8 +107,14 @@ func (d *corruptObjectDeleter) Delete(ctx context.Context, name string, deleteVa
klog.FromContext(ctx).V(1).Info("Going to perform unsafe object deletion", "object", klog.KRef(genericapirequest.NamespaceValue(ctx), name))
out := d.store.NewFunc()
storageOpts := storage.DeleteOptions{IgnoreStoreReadError: true}
// dropping preconditions, and keeping the admission
if err := storageBackend.Delete(ctx, key, out, nil, storage.ValidateObjectFunc(deleteValidation), nil, storageOpts); err != nil {
// we don't have the old object in the cache, neither can it be
// retrieved from the storage and decoded into an object
// successfully, so we do the following:
// a) skip preconditions check
// b) skip admission validation, rest.ValidateAllObjectFunc will "admit everything"
var nilPreconditions *storage.Preconditions = nil
var nilCachedExistingObject runtime.Object = nil
if err := storageBackend.Delete(ctx, key, out, nilPreconditions, rest.ValidateAllObjectFunc, nilCachedExistingObject, storageOpts); err != nil {
if storage.IsNotFound(err) {
// the DELETE succeeded, but we don't have the object since it's
// not retrievable from the storage, so we send a nil object

View File

@ -267,6 +267,50 @@ func TestUnsafeDeleteWithUnexpectedError(t *testing.T) {
}
}
func TestUnsafeDeleteWithAdmissionShouldBeSkipped(t *testing.T) {
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test")
destroyFunc, registry := NewTestGenericStoreRegistry(t)
defer destroyFunc()
// a) create the target object
object := &example.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Spec: example.PodSpec{NodeName: "machine"},
}
_, err := registry.Create(ctx, object, rest.ValidateAllObjectFunc, &metav1.CreateOptions{})
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
// b) wrap the storage layer to return corrupt object error
registry.Storage.Storage = &corruptStorage{
Interface: registry.Storage.Storage,
err: storage.NewCorruptObjError("key", fmt.Errorf("untransformable")),
}
// c) set up a corrupt object deleter for the registry
deleter := NewCorruptObjectDeleter(registry)
// d) try unsafe delete, but pass a validation that always fails
var admissionInvoked int
_, deleted, err := deleter.Delete(ctx, object.Name, func(_ context.Context, _ runtime.Object) error {
admissionInvoked++
return fmt.Errorf("admission was not skipped")
}, &metav1.DeleteOptions{
IgnoreStoreReadErrorWithClusterBreakingPotential: ptr.To[bool](true),
})
if err != nil {
t.Errorf("Unexpected error from Delete: %v", err)
}
if want, got := true, deleted; want != got {
t.Errorf("Expected deleted: %t, but got: %t", want, got)
}
if want, got := 0, admissionInvoked; want != got {
t.Errorf("Expected admission to be invoked %d time(s), but got: %d", want, got)
}
}
type corruptStorage struct {
storage.Interface
err error