github.com/verrazzano/verrazzano@v1.7.0/pkg/k8s/resource/resource.go (about) 1 // Copyright (c) 2022, 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package resource 5 6 import ( 7 "context" 8 spiErrors "github.com/verrazzano/verrazzano/pkg/controller/errors" 9 "github.com/verrazzano/verrazzano/pkg/log/vzlog" 10 "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/spi" 11 "k8s.io/apimachinery/pkg/api/errors" 12 "k8s.io/apimachinery/pkg/api/meta" 13 "k8s.io/apimachinery/pkg/types" 14 "reflect" 15 "sigs.k8s.io/controller-runtime/pkg/client" 16 ) 17 18 type Resource struct { 19 Namespace string 20 Name string 21 Client client.Client 22 Object client.Object 23 Log vzlog.VerrazzanoLogger 24 } 25 26 // CleanupResources deletes and removes finalizers from resources 27 func CleanupResources(ctx spi.ComponentContext, objects []client.Object) error { 28 for _, object := range objects { 29 err := Resource{ 30 Name: object.GetName(), 31 Namespace: object.GetNamespace(), 32 Client: ctx.Client(), 33 Object: object, 34 Log: ctx.Log(), 35 }.RemoveFinalizersAndDelete() 36 if err != nil { 37 ctx.Log().ErrorfThrottled("Unexpected error cleaning up resource %s/%s still exists: %s", object.GetName(), object.GetNamespace(), err.Error()) 38 return spiErrors.RetryableError{ 39 Source: ctx.GetComponent(), 40 Operation: ctx.GetOperation(), 41 Cause: err, 42 } 43 } 44 } 45 return nil 46 } 47 48 // VerifyResourcesDeleted verifies resources have been fully cleaned up 49 func VerifyResourcesDeleted(ctx spi.ComponentContext, objects []client.Object) error { 50 for _, object := range objects { 51 exists, err := Resource{ 52 Name: object.GetName(), 53 Namespace: object.GetNamespace(), 54 Client: ctx.Client(), 55 Object: object, 56 Log: ctx.Log(), 57 }.Exists() 58 if err != nil { 59 ctx.Log().ErrorfThrottled("Unexpected error checking if resource %s/%s still exists: %s", object.GetName(), object.GetNamespace(), err.Error()) 60 return spiErrors.RetryableError{ 61 Source: ctx.GetComponent(), 62 Operation: ctx.GetOperation(), 63 Cause: err, 64 } 65 } 66 if exists { 67 return spiErrors.RetryableError{ 68 Source: ctx.GetComponent(), 69 } 70 } 71 ctx.Log().Debugf("Verified that resource %s/%s has been successfully deleted", object.GetName(), object.GetNamespace()) 72 } 73 return nil 74 } 75 76 // Delete deletes a resource if it exists, not found error is ignored 77 func (r Resource) Delete() error { 78 r.Object.SetName(r.Name) 79 r.Object.SetNamespace(r.Namespace) 80 val := reflect.ValueOf(r.Object) 81 kind := val.Elem().Type().Name() 82 if kind == "Unstructured" { 83 kind = r.Object.GetObjectKind().GroupVersionKind().Kind 84 } 85 err := r.Client.Delete(context.TODO(), r.Object) 86 if err != nil { 87 // Ignore if CRD doesn't exist 88 if _, ok := err.(*meta.NoKindMatchError); ok { 89 return nil 90 } 91 if client.IgnoreNotFound(err) == nil { 92 return nil 93 } 94 return r.Log.ErrorfNewErr("Failed to delete the resource of type %s, named %s/%s: %v", kind, r.Object.GetNamespace(), r.Object.GetName(), err) 95 } 96 r.Log.Oncef("Successfully deleted %s %s/%s", kind, r.Object.GetNamespace(), r.Object.GetName()) 97 return nil 98 } 99 100 // RemoveFinializersAndDelete removes all finalizers from a resource and deletes the resource 101 func (r Resource) RemoveFinalizersAndDelete() error { 102 // always delete first, then remove finalizer to reduce the chance that a Rancher webhook 103 // will add it back (since the deletion timestamp will be non-zero) 104 err := r.Delete() 105 if err != nil { 106 return err 107 } 108 return r.RemoveFinalizers() 109 } 110 111 // RemoveFinalizers removes all finalizers from a resource 112 func (r Resource) RemoveFinalizers() error { 113 val := reflect.ValueOf(r.Object) 114 kind := val.Elem().Type().Name() 115 if kind == "Unstructured" { 116 kind = r.Object.GetObjectKind().GroupVersionKind().Kind 117 } 118 err := r.Client.Get(context.TODO(), types.NamespacedName{Namespace: r.Namespace, Name: r.Name}, r.Object) 119 if client.IgnoreNotFound(err) != nil { 120 return r.Log.ErrorfNewErr("Failed to get the resource of type %s, named %s/%s: %v", kind, r.Object.GetNamespace(), r.Object.GetName(), err) 121 } else if err == nil { 122 if len(r.Object.GetFinalizers()) != 0 { 123 r.Object.SetFinalizers([]string{}) 124 err = r.Client.Update(context.TODO(), r.Object) 125 if err != nil { 126 return r.Log.ErrorfNewErr("Failed to update the resource of type %s, named %s/%s: %v", kind, r.Object.GetNamespace(), r.Object.GetName(), err) 127 } 128 } 129 } 130 return nil 131 } 132 133 // Exists returns true if the Resource exists 134 func (r Resource) Exists() (bool, error) { 135 err := r.Client.Get(context.TODO(), types.NamespacedName{Namespace: r.Namespace, Name: r.Name}, r.Object) 136 if err != nil { 137 if errors.IsNotFound(err) { 138 return false, nil 139 } 140 // Ignore if CRD doesn't exist 141 if _, ok := err.(*meta.NoKindMatchError); ok { 142 return false, nil 143 } 144 return false, err 145 } 146 return true, nil 147 }