github.com/iter8-tools/iter8@v1.1.2/controllers/finalizer.go (about) 1 package controllers 2 3 import ( 4 "context" 5 "errors" 6 7 "github.com/iter8-tools/iter8/base/log" 8 "github.com/iter8-tools/iter8/controllers/k8sclient" 9 corev1 "k8s.io/api/core/v1" 10 kubeerrors "k8s.io/apimachinery/pkg/api/errors" 11 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 "k8s.io/apimachinery/pkg/runtime/schema" 13 "k8s.io/client-go/util/retry" 14 ) 15 16 const ( 17 // for application resources 18 iter8FinalizerStr = "iter8.tools/finalizer" 19 ) 20 21 // add Iter8 finalizer to an application resource 22 func addFinalizer(name string, namespace string, gvrShort string, client k8sclient.Interface, config *Config) { 23 err := retry.RetryOnConflict(retry.DefaultRetry, func() error { 24 // first, get the object 25 u, e := client.Resource(schema.GroupVersionResource{ 26 Group: config.ResourceTypes[gvrShort].Group, 27 Version: config.ResourceTypes[gvrShort].Version, 28 Resource: config.ResourceTypes[gvrShort].Resource, 29 }).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{}) 30 if e != nil { 31 return e 32 } 33 34 // get old and new finalizers 35 oldFinalizers := map[string]bool{} 36 newFinalizers := map[string]bool{} 37 if u.GetDeletionTimestamp() == nil { 38 for _, f := range u.GetFinalizers() { 39 oldFinalizers[f] = true 40 newFinalizers[f] = true 41 } 42 // insert Iter8 finalizer 43 newFinalizers[iter8FinalizerStr] = true 44 } 45 46 // the only way newFinalizers could be of a different length is if 47 // oldFinalizers didn't have iter8FinalizerStr 48 if len(oldFinalizers) != len(newFinalizers) { 49 log.Logger.Trace("oldFinalizers: ", oldFinalizers) 50 log.Logger.Trace("newFinalizers: ", newFinalizers) 51 finalizers := []string{} 52 for key := range newFinalizers { 53 finalizers = append(finalizers, key) 54 } 55 u.SetFinalizers(finalizers) 56 57 log.Logger.Trace("attempting to update resource with finalizer") 58 _, e := client.Resource(schema.GroupVersionResource{ 59 Group: config.ResourceTypes[gvrShort].Group, 60 Version: config.ResourceTypes[gvrShort].Version, 61 Resource: config.ResourceTypes[gvrShort].Resource, 62 }).Namespace(u.GetNamespace()).Update(context.TODO(), u, metav1.UpdateOptions{}) 63 if e != nil { 64 log.Logger.WithStackTrace(e.Error()).Error("error while updating resource with finalizer") 65 } else { 66 // broadcast event 67 68 // get resource for event broadcasting 69 r, err := client.Resource(schema.GroupVersionResource{ 70 Group: config.ResourceTypes[gvrShort].Group, 71 Version: config.ResourceTypes[gvrShort].Version, 72 Resource: config.ResourceTypes[gvrShort].Resource, 73 }).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{}) 74 if err != nil { 75 log.Logger.Warnf("could not get pod with name %s in namespace %s", name, namespace) 76 } else { 77 broadcastEvent(r, corev1.EventTypeNormal, "Added Iter8 finalizer", "Added Iter8 finalizer for resource", client) 78 } 79 } 80 return e 81 } 82 83 return nil 84 }) 85 86 if err != nil { 87 if kubeerrors.IsNotFound(err) { 88 log.Logger.Debug(err) 89 } else { 90 log.Logger.WithStackTrace(err.Error()).Error(errors.New("failed to add finalizer with retry")) 91 92 // get resource for event broadcasting 93 r, err := client.Resource(schema.GroupVersionResource{ 94 Group: config.ResourceTypes[gvrShort].Group, 95 Version: config.ResourceTypes[gvrShort].Version, 96 Resource: config.ResourceTypes[gvrShort].Resource, 97 }).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{}) 98 if err != nil { 99 log.Logger.Warnf("could not get pod with name %s in namespace %s", name, namespace) 100 } 101 102 broadcastEvent(r, corev1.EventTypeWarning, "Failed to add Iter8 finalizer", "Failed to add Iter8 finalizer for resource", client) 103 } 104 } 105 } 106 107 // remove Iter8 finalizer from an application resource 108 func removeFinalizer(name string, namespace string, gvrShort string, client k8sclient.Interface, config *Config) { 109 err := retry.RetryOnConflict(retry.DefaultRetry, func() error { 110 // first, get the object 111 u, e := client.Resource(schema.GroupVersionResource{ 112 Group: config.ResourceTypes[gvrShort].Group, 113 Version: config.ResourceTypes[gvrShort].Version, 114 Resource: config.ResourceTypes[gvrShort].Resource, 115 }).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{}) 116 if e != nil && kubeerrors.IsNotFound(e) { 117 return nil 118 } else if e != nil { 119 return e 120 } 121 122 if u.GetDeletionTimestamp() == nil { 123 log.Logger.Trace("object not terminating; will not remove finalizer") 124 return nil 125 } 126 127 // remove iter8 finalizer if present 128 var finalizers []string 129 for _, f := range u.GetFinalizers() { 130 if f != iter8FinalizerStr { 131 finalizers = append(finalizers, f) 132 } 133 } 134 135 if len(finalizers) < len(u.GetFinalizers()) { 136 // update finalizers in the object 137 // we do not want to remove non-Iter8 finalizers 138 if len(finalizers) == 0 { 139 u.SetFinalizers(nil) 140 } else { 141 u.SetFinalizers(finalizers) 142 } 143 144 // update object 145 _, e = client.Resource(schema.GroupVersionResource{ 146 Group: config.ResourceTypes[gvrShort].Group, 147 Version: config.ResourceTypes[gvrShort].Version, 148 Resource: config.ResourceTypes[gvrShort].Resource, 149 }).Namespace(u.GetNamespace()).Update(context.TODO(), u, metav1.UpdateOptions{}) 150 151 if e != nil { 152 // if object has been deleted, return 153 if kubeerrors.IsNotFound(e) { 154 return nil 155 } 156 } 157 } 158 159 return e 160 }) 161 162 if err != nil { 163 log.Logger.WithStackTrace(err.Error()).Error(errors.New("failed to delete Iter8 finalizer")) 164 165 // get resource for event broadcasting 166 r, err := client.Resource(schema.GroupVersionResource{ 167 Group: config.ResourceTypes[gvrShort].Group, 168 Version: config.ResourceTypes[gvrShort].Version, 169 Resource: config.ResourceTypes[gvrShort].Resource, 170 }).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{}) 171 if err != nil { 172 log.Logger.Warnf("could not get resource with name %s in namespace %s", name, namespace) 173 } 174 175 broadcastEvent(r, corev1.EventTypeWarning, "Failed to delete Iter8 finalizer", "Failed to delete Iter8 finalizer for resource", client) 176 } 177 }