...// ObjectMeta is metadata that all persisted resources must have, which includes all objects
// users must create.
typeObjectMetastruct{...// Populated by the system when a graceful deletion is requested.
// Read-only.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
DeletionTimestamp*Time`json:"deletionTimestamp,omitempty" protobuf:"bytes,9,opt,name=deletionTimestamp"`// Number of seconds allowed for this object to gracefully terminate before
// it will be removed from the system. Only set when deletionTimestamp is also set.
// May only be shortened.
// Read-only.
// +optional
DeletionGracePeriodSeconds*int64`json:"deletionGracePeriodSeconds,omitempty" protobuf:"varint,10,opt,name=deletionGracePeriodSeconds"`// Must be empty before the object is deleted from the registry. Each entry
// is an identifier for the responsible component that will remove the entry
// from the list. If the deletionTimestamp of the object is non-nil, entries
// in this list can only be removed.
// Finalizers may be processed and removed in any order. Order is NOT enforced
// because it introduces significant risk of stuck finalizers.
// finalizers is a shared field, any actor with permission can reorder it.
// If the finalizer list is processed in order, then this can lead to a situation
// in which the component responsible for the first finalizer in the list is
// waiting for a signal (field value, external system, or other) produced by a
// component responsible for a finalizer later in the list, resulting in a deadlock.
// Without enforced ordering finalizers are free to order amongst themselves and
// are not vulnerable to ordering changes in the list.
// +optional
// +patchStrategy=merge
Finalizers[]string`json:"finalizers,omitempty" patchStrategy:"merge" protobuf:"bytes,14,rep,name=finalizers"`...
Must be empty before the object is deleted from the registry. Each entry is an identifier for the responsible component that will remove the entry from the list. If the deletionTimestamp of the object is non-nil, entries in this list can only be removed. Finalizers may be processed and removed in any order. Order is NOT enforced because it introduces significant risk of stuck finalizers. finalizers is a shared field, any actor with permission can reorder it. If the finalizer list is processed in order, then this can lead to a situation in which the component responsible for the first finalizer in the list is waiting for a signal (field value, external system, or other) produced by a component responsible for a finalizer later in the list, resulting in a deadlock. Without enforced ordering finalizers are free to order amongst themselves and are not vulnerable to ordering changes in the list.
大膽假設
我認為上述的文字簡單來說有三個重點(以下的順序不重要)
If the deletionTimestamp of the object is non-nil, entries in this list can only be removed.
簡單來說當 deletionTimestamp 不是 nil 的時候需要先刪除 Finalizers 內的條目
Finalizers may be processed and removed in any order
Finalizers 條目的刪除順序不是固定的
Must be empty before the object is deleted from the registry.
再刪除這個物件前 Finalizers 條目必須是空的
func(ctrl*ApplicationController)processProjectQueueItem()(processNextbool){iforigProj.DeletionTimestamp!=nil&&origProj.HasFinalizer(){iferr:=ctrl.finalizeProjectDeletion(origProj.DeepCopy());err!=nil{log.Warnf("Failed to finalize project deletion: %v",err)}}return...}func(ctrl*ApplicationController)finalizeProjectDeletion(proj*appv1.AppProject)error{apps,err:=ctrl.appLister.Applications(ctrl.namespace).List(labels.Everything())iferr!=nil{returnerr}appsCount:=0fori:=rangeapps{ifapps[i].Spec.GetProject()==proj.Name{appsCount++break}}ifappsCount==0{returnctrl.removeProjectFinalizer(proj)}else{log.Infof("Cannot remove project '%s' finalizer as is referenced by %d applications",proj.Name,appsCount)}returnnil}func(ctrl*ApplicationController)removeProjectFinalizer(proj*appv1.AppProject)error{proj.RemoveFinalizer()varpatch[]bytepatch,_=json.Marshal(map[string]interface{}{"metadata":map[string]interface{}{"finalizers":proj.Finalizers,},})_,err:=ctrl.applicationClientset.ArgoprojV1alpha1().AppProjects(ctrl.namespace).Patch(context.Background(),proj.Name,types.MergePatchType,patch,metav1.PatchOptions{})returnerr}func(projAppProject)HasFinalizer()bool{returngetFinalizerIndex(proj.ObjectMeta,common.ResourcesFinalizerName)>-1}// getFinalizerIndex returns finalizer index in the list of object finalizers or -1 if finalizer does not exist
funcgetFinalizerIndex(metametav1.ObjectMeta,namestring)int{fori,finalizer:=rangemeta.Finalizers{iffinalizer==name{returni}}return-1}func(proj*AppProject)RemoveFinalizer(){setFinalizer(&proj.ObjectMeta,common.ResourcesFinalizerName,false)}// setFinalizer adds or removes finalizer with the specified name
funcsetFinalizer(meta*metav1.ObjectMeta,namestring,existbool){index:=getFinalizerIndex(*meta,name)ifexist!=(index>-1){ifindex>-1{meta.Finalizers[index]=meta.Finalizers[len(meta.Finalizers)-1]meta.Finalizers=meta.Finalizers[:len(meta.Finalizers)-1]}else{meta.Finalizers=append(meta.Finalizers,name)}}}
我把主要的判斷邏輯抓出來,可以看到大致上的邏輯有幾項
processProjectQueueItem function 裡面會判斷 Application 物件的 DeletionTimestamp 以及 Finalizers 內有沒有我們要關注的 key。