mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
namespace: remove gc finalizers based on delete options
This makes the behavior being consistent with generic store, The orphan finalizer should be removed if the delete options does not specify propagarionPolicy as orphan.
This commit is contained in:
parent
aa52140928
commit
a458e9bb85
@ -16,6 +16,7 @@ go_test(
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/registry/generic/testing:go_default_library",
|
||||
|
@ -185,17 +185,33 @@ func (r *REST) Delete(ctx context.Context, name string, options *metav1.DeleteOp
|
||||
existingNamespace.Status.Phase = api.NamespaceTerminating
|
||||
}
|
||||
|
||||
// Remove orphan finalizer if options.OrphanDependents = false.
|
||||
if options.OrphanDependents != nil && *options.OrphanDependents == false {
|
||||
// remove Orphan finalizer.
|
||||
newFinalizers := []string{}
|
||||
for i := range existingNamespace.ObjectMeta.Finalizers {
|
||||
finalizer := existingNamespace.ObjectMeta.Finalizers[i]
|
||||
if string(finalizer) != metav1.FinalizerOrphanDependents {
|
||||
newFinalizers = append(newFinalizers, finalizer)
|
||||
}
|
||||
// the current finalizers which are on namespace
|
||||
currentFinalizers := map[string]bool{}
|
||||
for _, f := range existingNamespace.Finalizers {
|
||||
currentFinalizers[f] = true
|
||||
}
|
||||
// the finalizers we should ensure on namespace
|
||||
shouldHaveFinalizers := map[string]bool{
|
||||
metav1.FinalizerOrphanDependents: shouldHaveOrphanFinalizer(options, currentFinalizers[metav1.FinalizerOrphanDependents]),
|
||||
metav1.FinalizerDeleteDependents: shouldHaveDeleteDependentsFinalizer(options, currentFinalizers[metav1.FinalizerDeleteDependents]),
|
||||
}
|
||||
// determine whether there are changes
|
||||
changeNeeded := false
|
||||
for finalizer, shouldHave := range shouldHaveFinalizers {
|
||||
changeNeeded = currentFinalizers[finalizer] != shouldHave || changeNeeded
|
||||
if shouldHave {
|
||||
currentFinalizers[finalizer] = true
|
||||
} else {
|
||||
delete(currentFinalizers, finalizer)
|
||||
}
|
||||
existingNamespace.ObjectMeta.Finalizers = newFinalizers
|
||||
}
|
||||
// make the changes if needed
|
||||
if changeNeeded {
|
||||
newFinalizers := []string{}
|
||||
for f := range currentFinalizers {
|
||||
newFinalizers = append(newFinalizers, f)
|
||||
}
|
||||
existingNamespace.Finalizers = newFinalizers
|
||||
}
|
||||
return existingNamespace, nil
|
||||
}),
|
||||
@ -222,6 +238,26 @@ func (r *REST) Delete(ctx context.Context, name string, options *metav1.DeleteOp
|
||||
return r.store.Delete(ctx, name, options)
|
||||
}
|
||||
|
||||
func shouldHaveOrphanFinalizer(options *metav1.DeleteOptions, haveOrphanFinalizer bool) bool {
|
||||
if options.OrphanDependents != nil {
|
||||
return *options.OrphanDependents
|
||||
}
|
||||
if options.PropagationPolicy != nil {
|
||||
return *options.PropagationPolicy == metav1.DeletePropagationOrphan
|
||||
}
|
||||
return haveOrphanFinalizer
|
||||
}
|
||||
|
||||
func shouldHaveDeleteDependentsFinalizer(options *metav1.DeleteOptions, haveDeleteDependentsFinalizer bool) bool {
|
||||
if options.OrphanDependents != nil {
|
||||
return *options.OrphanDependents == false
|
||||
}
|
||||
if options.PropagationPolicy != nil {
|
||||
return *options.PropagationPolicy == metav1.DeletePropagationForeground
|
||||
}
|
||||
return haveDeleteDependentsFinalizer
|
||||
}
|
||||
|
||||
func (e *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1beta1.Table, error) {
|
||||
return e.store.ConvertToTable(ctx, object, tableOptions)
|
||||
}
|
||||
|
@ -22,11 +22,13 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing"
|
||||
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/registry/registrytest"
|
||||
)
|
||||
@ -189,6 +191,217 @@ func TestDeleteNamespaceWithCompleteFinalizers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteWithGCFinalizers(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.store.DestroyFunc()
|
||||
|
||||
propagationBackground := metav1.DeletePropagationBackground
|
||||
propagationForeground := metav1.DeletePropagationForeground
|
||||
propagationOrphan := metav1.DeletePropagationOrphan
|
||||
trueVar := true
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
deleteOptions *metav1.DeleteOptions
|
||||
|
||||
existingFinalizers []string
|
||||
remainingFinalizers map[string]bool
|
||||
}{
|
||||
{
|
||||
name: "nil-with-orphan",
|
||||
deleteOptions: nil,
|
||||
existingFinalizers: []string{
|
||||
metav1.FinalizerOrphanDependents,
|
||||
},
|
||||
remainingFinalizers: map[string]bool{
|
||||
metav1.FinalizerOrphanDependents: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nil-with-delete",
|
||||
deleteOptions: nil,
|
||||
existingFinalizers: []string{
|
||||
metav1.FinalizerDeleteDependents,
|
||||
},
|
||||
remainingFinalizers: map[string]bool{
|
||||
metav1.FinalizerDeleteDependents: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nil-without-finalizers",
|
||||
deleteOptions: nil,
|
||||
existingFinalizers: []string{},
|
||||
remainingFinalizers: map[string]bool{},
|
||||
},
|
||||
{
|
||||
name: "propagation-background-with-orphan",
|
||||
deleteOptions: &metav1.DeleteOptions{
|
||||
PropagationPolicy: &propagationBackground,
|
||||
},
|
||||
existingFinalizers: []string{
|
||||
metav1.FinalizerOrphanDependents,
|
||||
},
|
||||
remainingFinalizers: map[string]bool{},
|
||||
},
|
||||
{
|
||||
name: "propagation-background-with-delete",
|
||||
deleteOptions: &metav1.DeleteOptions{
|
||||
PropagationPolicy: &propagationBackground,
|
||||
},
|
||||
existingFinalizers: []string{
|
||||
metav1.FinalizerDeleteDependents,
|
||||
},
|
||||
remainingFinalizers: map[string]bool{},
|
||||
},
|
||||
{
|
||||
name: "propagation-background-without-finalizers",
|
||||
deleteOptions: &metav1.DeleteOptions{
|
||||
PropagationPolicy: &propagationBackground,
|
||||
},
|
||||
existingFinalizers: []string{},
|
||||
remainingFinalizers: map[string]bool{},
|
||||
},
|
||||
{
|
||||
name: "propagation-foreground-with-orphan",
|
||||
deleteOptions: &metav1.DeleteOptions{
|
||||
PropagationPolicy: &propagationForeground,
|
||||
},
|
||||
existingFinalizers: []string{
|
||||
metav1.FinalizerOrphanDependents,
|
||||
},
|
||||
remainingFinalizers: map[string]bool{
|
||||
metav1.FinalizerDeleteDependents: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "propagation-foreground-with-delete",
|
||||
deleteOptions: &metav1.DeleteOptions{
|
||||
PropagationPolicy: &propagationForeground,
|
||||
},
|
||||
existingFinalizers: []string{
|
||||
metav1.FinalizerDeleteDependents,
|
||||
},
|
||||
remainingFinalizers: map[string]bool{
|
||||
metav1.FinalizerDeleteDependents: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "propagation-foreground-without-finalizers",
|
||||
deleteOptions: &metav1.DeleteOptions{
|
||||
PropagationPolicy: &propagationForeground,
|
||||
},
|
||||
existingFinalizers: []string{},
|
||||
remainingFinalizers: map[string]bool{
|
||||
metav1.FinalizerDeleteDependents: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "propagation-orphan-with-orphan",
|
||||
deleteOptions: &metav1.DeleteOptions{
|
||||
PropagationPolicy: &propagationOrphan,
|
||||
},
|
||||
existingFinalizers: []string{
|
||||
metav1.FinalizerOrphanDependents,
|
||||
},
|
||||
remainingFinalizers: map[string]bool{
|
||||
metav1.FinalizerOrphanDependents: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "propagation-orphan-with-delete",
|
||||
deleteOptions: &metav1.DeleteOptions{
|
||||
PropagationPolicy: &propagationOrphan,
|
||||
},
|
||||
existingFinalizers: []string{
|
||||
metav1.FinalizerDeleteDependents,
|
||||
},
|
||||
remainingFinalizers: map[string]bool{
|
||||
metav1.FinalizerOrphanDependents: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "propagation-orphan-without-finalizers",
|
||||
deleteOptions: &metav1.DeleteOptions{
|
||||
PropagationPolicy: &propagationOrphan,
|
||||
},
|
||||
existingFinalizers: []string{},
|
||||
remainingFinalizers: map[string]bool{
|
||||
metav1.FinalizerOrphanDependents: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "orphan-dependents-with-orphan",
|
||||
deleteOptions: &metav1.DeleteOptions{
|
||||
OrphanDependents: &trueVar,
|
||||
},
|
||||
existingFinalizers: []string{
|
||||
metav1.FinalizerOrphanDependents,
|
||||
},
|
||||
remainingFinalizers: map[string]bool{
|
||||
metav1.FinalizerOrphanDependents: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "orphan-dependents-with-delete",
|
||||
deleteOptions: &metav1.DeleteOptions{
|
||||
OrphanDependents: &trueVar,
|
||||
},
|
||||
existingFinalizers: []string{
|
||||
metav1.FinalizerDeleteDependents,
|
||||
},
|
||||
remainingFinalizers: map[string]bool{
|
||||
metav1.FinalizerOrphanDependents: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "orphan-dependents-without-finalizers",
|
||||
deleteOptions: &metav1.DeleteOptions{
|
||||
OrphanDependents: &trueVar,
|
||||
},
|
||||
existingFinalizers: []string{},
|
||||
remainingFinalizers: map[string]bool{
|
||||
metav1.FinalizerOrphanDependents: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
key := "namespaces/" + test.name
|
||||
ctx := genericapirequest.NewContext()
|
||||
namespace := &api.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: test.name,
|
||||
Finalizers: test.existingFinalizers,
|
||||
},
|
||||
Spec: api.NamespaceSpec{
|
||||
Finalizers: []api.FinalizerName{},
|
||||
},
|
||||
Status: api.NamespaceStatus{Phase: api.NamespaceActive},
|
||||
}
|
||||
if err := storage.store.Storage.Create(ctx, key, namespace, nil, 0, false); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
var obj runtime.Object
|
||||
var err error
|
||||
if obj, _, err = storage.Delete(ctx, test.name, test.deleteOptions); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
ns, ok := obj.(*api.Namespace)
|
||||
if !ok {
|
||||
t.Errorf("unexpected object kind: %+v", obj)
|
||||
}
|
||||
if len(ns.Finalizers) != len(test.remainingFinalizers) {
|
||||
t.Errorf("%s: unexpected remaining finalizers: %v", test.name, ns.Finalizers)
|
||||
}
|
||||
for _, f := range ns.Finalizers {
|
||||
if test.remainingFinalizers[f] != true {
|
||||
t.Errorf("%s: unexpected finalizer %s", test.name, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestShortNames(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
|
Loading…
Reference in New Issue
Block a user