mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-08 11:38:15 +00:00
Merge pull request #51148 from ironcladlou/gc-finalizer-decoupling
Automatic merge from submit-queue (batch tested with PRs 51148, 50816, 49741, 50858, 51223) Enable finalizers independent of GC enablement Decouple finalizer processing from garbage collection configuration. Finalizers should be effective even when garbage collection is disabled for a given store. Fixes https://github.com/kubernetes/kubernetes/issues/50528. ```release-note NONE ``` /cc @kubernetes/sig-api-machinery-bugs /cc @caesarxuchao @liggitt @sttts @pmorie
This commit is contained in:
commit
7edab23997
@ -442,12 +442,8 @@ func (e *Store) WaitForInitialized(ctx genericapirequest.Context, obj runtime.Ob
|
|||||||
|
|
||||||
// shouldDeleteDuringUpdate checks if a Update is removing all the object's
|
// shouldDeleteDuringUpdate checks if a Update is removing all the object's
|
||||||
// finalizers. If so, it further checks if the object's
|
// finalizers. If so, it further checks if the object's
|
||||||
// DeletionGracePeriodSeconds is 0. If so, it returns true. If garbage collection
|
// DeletionGracePeriodSeconds is 0.
|
||||||
// is disabled it always returns false.
|
|
||||||
func (e *Store) shouldDeleteDuringUpdate(ctx genericapirequest.Context, key string, obj, existing runtime.Object) bool {
|
func (e *Store) shouldDeleteDuringUpdate(ctx genericapirequest.Context, key string, obj, existing runtime.Object) bool {
|
||||||
if !e.EnableGarbageCollection {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
newMeta, err := meta.Accessor(obj)
|
newMeta, err := meta.Accessor(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utilruntime.HandleError(err)
|
utilruntime.HandleError(err)
|
||||||
@ -765,9 +761,18 @@ func shouldDeleteDependents(e *Store, accessor metav1.Object, options *metav1.De
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// deletionFinalizers returns the deletion finalizers we should set on the object and a bool indicate they did or
|
// deletionFinalizersForGarbageCollection analyzes the object and delete options
|
||||||
// did not change.
|
// to determine whether the object is in need of finalization by the garbage
|
||||||
func deletionFinalizers(e *Store, accessor metav1.Object, options *metav1.DeleteOptions) (bool, []string) {
|
// collector. If so, returns the set of deletion finalizers to apply and a bool
|
||||||
|
// indicating whether the finalizer list has changed and is in need of updating.
|
||||||
|
//
|
||||||
|
// The finalizers returned are intended to be handled by the garbage collector.
|
||||||
|
// If garbage collection is disabled for the store, this function returns false
|
||||||
|
// to ensure finalizers aren't set which will never be cleared.
|
||||||
|
func deletionFinalizersForGarbageCollection(e *Store, accessor metav1.Object, options *metav1.DeleteOptions) (bool, []string) {
|
||||||
|
if !e.EnableGarbageCollection {
|
||||||
|
return false, []string{}
|
||||||
|
}
|
||||||
shouldOrphan := shouldOrphanDependents(e, accessor, options)
|
shouldOrphan := shouldOrphanDependents(e, accessor, options)
|
||||||
shouldDeleteDependentInForeground := shouldDeleteDependents(e, accessor, options)
|
shouldDeleteDependentInForeground := shouldDeleteDependents(e, accessor, options)
|
||||||
newFinalizers := []string{}
|
newFinalizers := []string{}
|
||||||
@ -816,72 +821,6 @@ func markAsDeleting(obj runtime.Object) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateForGracefulDeletion and updateForGracefulDeletionAndFinalizers both
|
|
||||||
// implement deletion flows for graceful deletion. Graceful deletion is
|
|
||||||
// implemented as setting the deletion timestamp in an update. If the
|
|
||||||
// implementation of graceful deletion is changed, both of these methods
|
|
||||||
// should be changed together.
|
|
||||||
|
|
||||||
// updateForGracefulDeletion updates the given object for graceful deletion by
|
|
||||||
// setting the deletion timestamp and grace period seconds and returns:
|
|
||||||
//
|
|
||||||
// 1. an error
|
|
||||||
// 2. a boolean indicating that the object was not found, but it should be
|
|
||||||
// ignored
|
|
||||||
// 3. a boolean indicating that the object's grace period is exhausted and it
|
|
||||||
// should be deleted immediately
|
|
||||||
// 4. a new output object with the state that was updated
|
|
||||||
// 5. a copy of the last existing state of the object
|
|
||||||
func (e *Store) updateForGracefulDeletion(ctx genericapirequest.Context, name, key string, options *metav1.DeleteOptions, preconditions storage.Preconditions, in runtime.Object) (err error, ignoreNotFound, deleteImmediately bool, out, lastExisting runtime.Object) {
|
|
||||||
lastGraceful := int64(0)
|
|
||||||
out = e.NewFunc()
|
|
||||||
err = e.Storage.GuaranteedUpdate(
|
|
||||||
ctx,
|
|
||||||
key,
|
|
||||||
out,
|
|
||||||
false, /* ignoreNotFound */
|
|
||||||
&preconditions,
|
|
||||||
storage.SimpleUpdate(func(existing runtime.Object) (runtime.Object, error) {
|
|
||||||
graceful, pendingGraceful, err := rest.BeforeDelete(e.DeleteStrategy, ctx, existing, options)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if pendingGraceful {
|
|
||||||
return nil, errAlreadyDeleting
|
|
||||||
}
|
|
||||||
if !graceful {
|
|
||||||
return nil, errDeleteNow
|
|
||||||
}
|
|
||||||
lastGraceful = *options.GracePeriodSeconds
|
|
||||||
lastExisting = existing
|
|
||||||
return existing, nil
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
switch err {
|
|
||||||
case nil:
|
|
||||||
if lastGraceful > 0 {
|
|
||||||
return nil, false, false, out, lastExisting
|
|
||||||
}
|
|
||||||
// If we are here, the registry supports grace period mechanism and
|
|
||||||
// we are intentionally delete gracelessly. In this case, we may
|
|
||||||
// enter a race with other k8s components. If other component wins
|
|
||||||
// the race, the object will not be found, and we should tolerate
|
|
||||||
// the NotFound error. See
|
|
||||||
// https://github.com/kubernetes/kubernetes/issues/19403 for
|
|
||||||
// details.
|
|
||||||
return nil, true, true, out, lastExisting
|
|
||||||
case errDeleteNow:
|
|
||||||
// we've updated the object to have a zero grace period, or it's already at 0, so
|
|
||||||
// we should fall through and truly delete the object.
|
|
||||||
return nil, false, true, out, lastExisting
|
|
||||||
case errAlreadyDeleting:
|
|
||||||
out, err = e.finalizeDelete(ctx, in, true)
|
|
||||||
return err, false, false, out, lastExisting
|
|
||||||
default:
|
|
||||||
return storeerr.InterpretUpdateError(err, e.qualifiedResourceFromContext(ctx), name), false, false, out, lastExisting
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateForGracefulDeletionAndFinalizers updates the given object for
|
// updateForGracefulDeletionAndFinalizers updates the given object for
|
||||||
// graceful deletion and finalization by setting the deletion timestamp and
|
// graceful deletion and finalization by setting the deletion timestamp and
|
||||||
// grace period seconds (graceful deletion) and updating the list of
|
// grace period seconds (graceful deletion) and updating the list of
|
||||||
@ -921,7 +860,7 @@ func (e *Store) updateForGracefulDeletionAndFinalizers(ctx genericapirequest.Con
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
needsUpdate, newFinalizers := deletionFinalizers(e, existingAccessor, options)
|
needsUpdate, newFinalizers := deletionFinalizersForGarbageCollection(e, existingAccessor, options)
|
||||||
if needsUpdate {
|
if needsUpdate {
|
||||||
existingAccessor.SetFinalizers(newFinalizers)
|
existingAccessor.SetFinalizers(newFinalizers)
|
||||||
}
|
}
|
||||||
@ -1013,18 +952,12 @@ func (e *Store) Delete(ctx genericapirequest.Context, name string, options *meta
|
|||||||
|
|
||||||
// Handle combinations of graceful deletion and finalization by issuing
|
// Handle combinations of graceful deletion and finalization by issuing
|
||||||
// the correct updates.
|
// the correct updates.
|
||||||
if e.EnableGarbageCollection {
|
shouldUpdateFinalizers, _ := deletionFinalizersForGarbageCollection(e, accessor, options)
|
||||||
shouldUpdateFinalizers, _ := deletionFinalizers(e, accessor, options)
|
// TODO: remove the check, because we support no-op updates now.
|
||||||
// TODO: remove the check, because we support no-op updates now.
|
if graceful || pendingFinalizers || shouldUpdateFinalizers {
|
||||||
if graceful || pendingFinalizers || shouldUpdateFinalizers {
|
err, ignoreNotFound, deleteImmediately, out, lastExisting = e.updateForGracefulDeletionAndFinalizers(ctx, name, key, options, preconditions, obj)
|
||||||
err, ignoreNotFound, deleteImmediately, out, lastExisting = e.updateForGracefulDeletionAndFinalizers(ctx, name, key, options, preconditions, obj)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO: remove the check on graceful, because we support no-op updates now.
|
|
||||||
if graceful {
|
|
||||||
err, ignoreNotFound, deleteImmediately, out, lastExisting = e.updateForGracefulDeletion(ctx, name, key, options, preconditions, obj)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// !deleteImmediately covers all cases where err != nil. We keep both to be future-proof.
|
// !deleteImmediately covers all cases where err != nil. We keep both to be future-proof.
|
||||||
if !deleteImmediately || err != nil {
|
if !deleteImmediately || err != nil {
|
||||||
return out, false, err
|
return out, false, err
|
||||||
|
@ -931,56 +931,62 @@ func TestGracefulStoreHandleFinalizers(t *testing.T) {
|
|||||||
|
|
||||||
testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test")
|
testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test")
|
||||||
destroyFunc, registry := NewTestGenericStoreRegistry(t)
|
destroyFunc, registry := NewTestGenericStoreRegistry(t)
|
||||||
registry.EnableGarbageCollection = true
|
|
||||||
defaultDeleteStrategy := testRESTStrategy{scheme, names.SimpleNameGenerator, true, false, true}
|
defaultDeleteStrategy := testRESTStrategy{scheme, names.SimpleNameGenerator, true, false, true}
|
||||||
registry.DeleteStrategy = testGracefulStrategy{defaultDeleteStrategy}
|
registry.DeleteStrategy = testGracefulStrategy{defaultDeleteStrategy}
|
||||||
defer destroyFunc()
|
defer destroyFunc()
|
||||||
// create pod
|
|
||||||
_, err := registry.Create(testContext, podWithFinalizer, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete the pod with grace period=0, the pod should still exist because it has a finalizer
|
gcStates := []bool{true, false}
|
||||||
_, wasDeleted, err := registry.Delete(testContext, podWithFinalizer.Name, metav1.NewDeleteOptions(0))
|
for _, gcEnabled := range gcStates {
|
||||||
if err != nil {
|
t.Logf("garbage collection enabled: %t", gcEnabled)
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
registry.EnableGarbageCollection = gcEnabled
|
||||||
}
|
|
||||||
if wasDeleted {
|
|
||||||
t.Errorf("unexpected, pod %s should not have been deleted immediately", podWithFinalizer.Name)
|
|
||||||
}
|
|
||||||
_, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
updatedPodWithFinalizer := &example.Pod{
|
// create pod
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion},
|
_, err := registry.Create(testContext, podWithFinalizer, false)
|
||||||
Spec: example.PodSpec{NodeName: "machine"},
|
if err != nil {
|
||||||
}
|
t.Errorf("Unexpected error: %v", err)
|
||||||
_, _, err = registry.Update(testContext, updatedPodWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(updatedPodWithFinalizer, scheme))
|
}
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// the object should still exist, because it still has a finalizer
|
// delete the pod with grace period=0, the pod should still exist because it has a finalizer
|
||||||
_, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{})
|
_, wasDeleted, err := registry.Delete(testContext, podWithFinalizer.Name, metav1.NewDeleteOptions(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
if wasDeleted {
|
||||||
|
t.Errorf("unexpected, pod %s should not have been deleted immediately", podWithFinalizer.Name)
|
||||||
|
}
|
||||||
|
_, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
podWithNoFinalizer := &example.Pod{
|
updatedPodWithFinalizer := &example.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion},
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion},
|
||||||
Spec: example.PodSpec{NodeName: "anothermachine"},
|
Spec: example.PodSpec{NodeName: "machine"},
|
||||||
}
|
}
|
||||||
_, _, err = registry.Update(testContext, podWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(podWithNoFinalizer, scheme))
|
_, _, err = registry.Update(testContext, updatedPodWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(updatedPodWithFinalizer, scheme))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
// the pod should be removed, because its finalizer is removed
|
|
||||||
_, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{})
|
// the object should still exist, because it still has a finalizer
|
||||||
if !errors.IsNotFound(err) {
|
_, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{})
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
podWithNoFinalizer := &example.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion},
|
||||||
|
Spec: example.PodSpec{NodeName: "anothermachine"},
|
||||||
|
}
|
||||||
|
_, _, err = registry.Update(testContext, podWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(podWithNoFinalizer, scheme))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
// the pod should be removed, because its finalizer is removed
|
||||||
|
_, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{})
|
||||||
|
if !errors.IsNotFound(err) {
|
||||||
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1030,73 +1036,79 @@ func TestNonGracefulStoreHandleFinalizers(t *testing.T) {
|
|||||||
|
|
||||||
testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test")
|
testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test")
|
||||||
destroyFunc, registry := NewTestGenericStoreRegistry(t)
|
destroyFunc, registry := NewTestGenericStoreRegistry(t)
|
||||||
registry.EnableGarbageCollection = true
|
|
||||||
defer destroyFunc()
|
defer destroyFunc()
|
||||||
// create pod
|
gcStates := []bool{true, false}
|
||||||
_, err := registry.Create(testContext, podWithFinalizer, false)
|
for _, gcEnabled := range gcStates {
|
||||||
if err != nil {
|
t.Logf("garbage collection enabled: %t", gcEnabled)
|
||||||
t.Errorf("Unexpected error: %v", err)
|
registry.EnableGarbageCollection = gcEnabled
|
||||||
}
|
|
||||||
|
|
||||||
// delete object with nil delete options doesn't delete the object
|
// create pod
|
||||||
_, wasDeleted, err := registry.Delete(testContext, podWithFinalizer.Name, nil)
|
_, err := registry.Create(testContext, podWithFinalizer, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if wasDeleted {
|
|
||||||
t.Errorf("unexpected, pod %s should not have been deleted immediately", podWithFinalizer.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// the object should still exist
|
// delete object with nil delete options doesn't delete the object
|
||||||
obj, err := registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{})
|
_, wasDeleted, err := registry.Delete(testContext, podWithFinalizer.Name, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
podWithFinalizer, ok := obj.(*example.Pod)
|
if wasDeleted {
|
||||||
if !ok {
|
t.Errorf("unexpected, pod %s should not have been deleted immediately", podWithFinalizer.Name)
|
||||||
t.Errorf("Unexpected object: %#v", obj)
|
}
|
||||||
}
|
|
||||||
if podWithFinalizer.ObjectMeta.DeletionTimestamp == nil {
|
|
||||||
t.Errorf("Expect the object to have DeletionTimestamp set, but got %#v", podWithFinalizer.ObjectMeta)
|
|
||||||
}
|
|
||||||
if podWithFinalizer.ObjectMeta.DeletionGracePeriodSeconds == nil || *podWithFinalizer.ObjectMeta.DeletionGracePeriodSeconds != 0 {
|
|
||||||
t.Errorf("Expect the object to have 0 DeletionGracePeriodSecond, but got %#v", podWithFinalizer.ObjectMeta)
|
|
||||||
}
|
|
||||||
if podWithFinalizer.Generation <= initialGeneration {
|
|
||||||
t.Errorf("Deletion didn't increase Generation.")
|
|
||||||
}
|
|
||||||
|
|
||||||
updatedPodWithFinalizer := &example.Pod{
|
// the object should still exist
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion},
|
obj, err := registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{})
|
||||||
Spec: example.PodSpec{NodeName: "machine"},
|
if err != nil {
|
||||||
}
|
t.Errorf("Unexpected error: %v", err)
|
||||||
_, _, err = registry.Update(testContext, updatedPodWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(updatedPodWithFinalizer, scheme))
|
}
|
||||||
if err != nil {
|
podWithFinalizer, ok := obj.(*example.Pod)
|
||||||
t.Errorf("Unexpected error: %v", err)
|
if !ok {
|
||||||
}
|
t.Errorf("Unexpected object: %#v", obj)
|
||||||
|
}
|
||||||
|
if podWithFinalizer.ObjectMeta.DeletionTimestamp == nil {
|
||||||
|
t.Errorf("Expect the object to have DeletionTimestamp set, but got %#v", podWithFinalizer.ObjectMeta)
|
||||||
|
}
|
||||||
|
if podWithFinalizer.ObjectMeta.DeletionGracePeriodSeconds == nil || *podWithFinalizer.ObjectMeta.DeletionGracePeriodSeconds != 0 {
|
||||||
|
t.Errorf("Expect the object to have 0 DeletionGracePeriodSecond, but got %#v", podWithFinalizer.ObjectMeta)
|
||||||
|
}
|
||||||
|
if podWithFinalizer.Generation <= initialGeneration {
|
||||||
|
t.Errorf("Deletion didn't increase Generation.")
|
||||||
|
}
|
||||||
|
|
||||||
// the object should still exist, because it still has a finalizer
|
updatedPodWithFinalizer := &example.Pod{
|
||||||
obj, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{})
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion},
|
||||||
if err != nil {
|
Spec: example.PodSpec{NodeName: "machine"},
|
||||||
t.Errorf("Unexpected error: %v", err)
|
}
|
||||||
}
|
_, _, err = registry.Update(testContext, updatedPodWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(updatedPodWithFinalizer, scheme))
|
||||||
podWithFinalizer, ok = obj.(*example.Pod)
|
if err != nil {
|
||||||
if !ok {
|
t.Errorf("Unexpected error: %v", err)
|
||||||
t.Errorf("Unexpected object: %#v", obj)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
podWithNoFinalizer := &example.Pod{
|
// the object should still exist, because it still has a finalizer
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion},
|
obj, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{})
|
||||||
Spec: example.PodSpec{NodeName: "anothermachine"},
|
if err != nil {
|
||||||
}
|
t.Errorf("Unexpected error: %v", err)
|
||||||
_, _, err = registry.Update(testContext, podWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(podWithNoFinalizer, scheme))
|
}
|
||||||
if err != nil {
|
podWithFinalizer, ok = obj.(*example.Pod)
|
||||||
t.Errorf("Unexpected error: %v", err)
|
if !ok {
|
||||||
}
|
t.Errorf("Unexpected object: %#v", obj)
|
||||||
// the pod should be removed, because its finalizer is removed
|
}
|
||||||
_, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{})
|
|
||||||
if !errors.IsNotFound(err) {
|
podWithNoFinalizer := &example.Pod{
|
||||||
t.Errorf("Unexpected error: %v", err)
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion},
|
||||||
|
Spec: example.PodSpec{NodeName: "anothermachine"},
|
||||||
|
}
|
||||||
|
_, _, err = registry.Update(testContext, podWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(podWithNoFinalizer, scheme))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
// the pod should be removed, because its finalizer is removed
|
||||||
|
_, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{})
|
||||||
|
if !errors.IsNotFound(err) {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user