1
16
17 package garbagecollector
18
19 import (
20 "context"
21 "encoding/json"
22 "fmt"
23
24 "k8s.io/apimachinery/pkg/api/errors"
25 "k8s.io/apimachinery/pkg/api/meta"
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 "k8s.io/apimachinery/pkg/runtime/schema"
28 "k8s.io/apimachinery/pkg/types"
29 "k8s.io/client-go/util/retry"
30 "k8s.io/klog/v2"
31 )
32
33
34 func resourceDefaultNamespace(namespaced bool, defaultNamespace string) string {
35 if namespaced {
36 return defaultNamespace
37 }
38 return ""
39 }
40
41
42
43 func (gc *GarbageCollector) apiResource(apiVersion, kind string) (schema.GroupVersionResource, bool, error) {
44 fqKind := schema.FromAPIVersionAndKind(apiVersion, kind)
45 mapping, err := gc.restMapper.RESTMapping(fqKind.GroupKind(), fqKind.Version)
46 if err != nil {
47 return schema.GroupVersionResource{}, false, newRESTMappingError(kind, apiVersion)
48 }
49 return mapping.Resource, mapping.Scope == meta.RESTScopeNamespace, nil
50 }
51
52 func (gc *GarbageCollector) deleteObject(item objectReference, policy *metav1.DeletionPropagation) error {
53 resource, namespaced, err := gc.apiResource(item.APIVersion, item.Kind)
54 if err != nil {
55 return err
56 }
57 uid := item.UID
58 preconditions := metav1.Preconditions{UID: &uid}
59 deleteOptions := metav1.DeleteOptions{Preconditions: &preconditions, PropagationPolicy: policy}
60 return gc.metadataClient.Resource(resource).Namespace(resourceDefaultNamespace(namespaced, item.Namespace)).Delete(context.TODO(), item.Name, deleteOptions)
61 }
62
63 func (gc *GarbageCollector) getObject(item objectReference) (*metav1.PartialObjectMetadata, error) {
64 resource, namespaced, err := gc.apiResource(item.APIVersion, item.Kind)
65 if err != nil {
66 return nil, err
67 }
68 namespace := resourceDefaultNamespace(namespaced, item.Namespace)
69 if namespaced && len(namespace) == 0 {
70
71
72 return nil, namespacedOwnerOfClusterScopedObjectErr
73 }
74 return gc.metadataClient.Resource(resource).Namespace(namespace).Get(context.TODO(), item.Name, metav1.GetOptions{})
75 }
76
77 func (gc *GarbageCollector) patchObject(item objectReference, patch []byte, pt types.PatchType) (*metav1.PartialObjectMetadata, error) {
78 resource, namespaced, err := gc.apiResource(item.APIVersion, item.Kind)
79 if err != nil {
80 return nil, err
81 }
82 return gc.metadataClient.Resource(resource).Namespace(resourceDefaultNamespace(namespaced, item.Namespace)).Patch(context.TODO(), item.Name, pt, patch, metav1.PatchOptions{})
83 }
84
85 func (gc *GarbageCollector) removeFinalizer(logger klog.Logger, owner *node, targetFinalizer string) error {
86 err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
87 ownerObject, err := gc.getObject(owner.identity)
88 if errors.IsNotFound(err) {
89 return nil
90 }
91 if err != nil {
92 return fmt.Errorf("cannot finalize owner %s, because cannot get it: %v. The garbage collector will retry later", owner.identity, err)
93 }
94 accessor, err := meta.Accessor(ownerObject)
95 if err != nil {
96 return fmt.Errorf("cannot access the owner object %v: %v. The garbage collector will retry later", ownerObject, err)
97 }
98 finalizers := accessor.GetFinalizers()
99 var newFinalizers []string
100 found := false
101 for _, f := range finalizers {
102 if f == targetFinalizer {
103 found = true
104 continue
105 }
106 newFinalizers = append(newFinalizers, f)
107 }
108 if !found {
109 logger.V(5).Info("finalizer already removed from object", "finalizer", targetFinalizer, "object", owner.identity)
110 return nil
111 }
112
113
114 patch, err := json.Marshal(&objectForFinalizersPatch{
115 ObjectMetaForFinalizersPatch: ObjectMetaForFinalizersPatch{
116 ResourceVersion: accessor.GetResourceVersion(),
117 Finalizers: newFinalizers,
118 },
119 })
120 if err != nil {
121 return fmt.Errorf("unable to finalize %s due to an error serializing patch: %v", owner.identity, err)
122 }
123 _, err = gc.patchObject(owner.identity, patch, types.MergePatchType)
124 return err
125 })
126 if errors.IsConflict(err) {
127 return fmt.Errorf("updateMaxRetries(%d) has reached. The garbage collector will retry later for owner %v", retry.DefaultBackoff.Steps, owner.identity)
128 }
129 return err
130 }
131
View as plain text