@@ -10,6 +10,7 @@ import (
1010 "github.com/red-hat-storage/ocs-client-operator/api/v1alpha1"
1111 "github.com/red-hat-storage/ocs-client-operator/pkg/utils"
1212 providerClient "github.com/red-hat-storage/ocs-operator/services/provider/api/v4/client"
13+ corev1 "k8s.io/api/core/v1"
1314 storagev1 "k8s.io/api/storage/v1"
1415 "k8s.io/apimachinery/pkg/api/errors"
1516 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -25,8 +26,9 @@ import (
2526)
2627
2728const (
28- operatorObcFinalizer = "ocs-client-operator.ocs.openshift.io/obc"
29+ ObcFinalizer = nbv1 . ObjectBucketFinalizer
2930 ObjectBucketClaimStatusPhaseFailed = "Failed"
31+ ObjectBucketClaimStatusPhaseBound = "Bound"
3032)
3133
3234// OBCReconciler reconciles a ObjectBucketClaim object
@@ -66,8 +68,11 @@ func (r *OBCReconciler) SetupWithManager(mgr ctrl.Manager) error {
6668
6769//+kubebuilder:rbac:groups=objectbucket.io,resources=objectbucketclaims,verbs=get;list;watch;update
6870//+kubebuilder:rbac:groups=objectbucket.io,resources=objectbucketclaims/status,verbs=get;update;patch
71+ //+kubebuilder:rbac:groups=objectbucket.io,resources=objectbuckets,verbs=get;list;watch;update;delete
6972//+kubebuilder:rbac:groups=ocs.openshift.io,resources=storageclients,verbs=get
7073//+kubebuilder:rbac:groups=storage.k8s.io,resources=storageclasses,verbs=get
74+ //+kubebuilder:rbac:groups="",resources=configmaps,verbs=get;update
75+ //+kubebuilder:rbac:groups="",resources=secrets,verbs=get;update
7176
7277func (r * OBCReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (ctrl.Result , error ) {
7378 r .ctx = ctx
@@ -97,8 +102,20 @@ func (r *OBCReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
97102 r .log .Error (err , "failed to notify provider of OBC deletion" , "namespaced/name" , client .ObjectKeyFromObject (obc ))
98103 return reconcile.Result {}, fmt .Errorf ("failed to delete the OBC on provider cluster: %v" , err )
99104 }
100- if controllerutil .RemoveFinalizer (obc , operatorObcFinalizer ) {
101- r .log .Info ("removing finalizer from OBC." , "namespaced/name" , client .ObjectKeyFromObject (obc ))
105+ if obc .Status .Phase == ObjectBucketClaimStatusPhaseBound {
106+ r .log .Info ("OBC is Bound - release resources" , "namespaced/name" , client .ObjectKeyFromObject (obc ))
107+ ob , cm , secret , errs := r .getResources (obc )
108+ if len (errs ) > 0 {
109+ r .log .Error (errs [0 ], "failed to get related resources for OBC delete" )
110+ return reconcile.Result {}, fmt .Errorf ("failed to get related resources for OBC delete: %v" , errs )
111+ }
112+ if err := r .deleteResources (ob , cm , secret , obc ); err != nil {
113+ r .log .Error (err , "failed to delete resources for OBC delete" )
114+ return reconcile.Result {}, fmt .Errorf ("failed to delete resources for OBC delete: %v" , err )
115+ }
116+ }
117+ if controllerutil .RemoveFinalizer (obc , ObcFinalizer ) {
118+ r .log .Info ("removing finalizer from OBC" , "namespaced/name" , client .ObjectKeyFromObject (obc ))
102119 if err := r .Update (r .ctx , obc ); err != nil {
103120 r .log .Info ("Failed to remove finalizer from OBC" , "namespaced/name" , client .ObjectKeyFromObject (obc ))
104121 return reconcile.Result {}, fmt .Errorf ("failed to remove finalizer from OBC: %v" , err )
@@ -108,8 +125,8 @@ func (r *OBCReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
108125 }
109126
110127 r .log .Info ("OBC created" , "namespace" , obc .Namespace , "name" , obc .Name )
111- if controllerutil .AddFinalizer (obc , operatorObcFinalizer ) {
112- r .log .Info ("Finalizer not found for OBC. Adding finalizer. " , "namespaced/name" , client .ObjectKeyFromObject (obc ))
128+ if controllerutil .AddFinalizer (obc , ObcFinalizer ) {
129+ r .log .Info ("Finalizer not found for OBC. Adding finalizer" , "namespaced/name" , client .ObjectKeyFromObject (obc ))
113130 if err := r .Update (r .ctx , obc ); err != nil {
114131 r .log .Info ("Failed to add finalizer to OBC" , "namespaced/name" , client .ObjectKeyFromObject (obc ))
115132 return reconcile.Result {}, fmt .Errorf ("failed to add finalizer to OBC: %v" , err )
@@ -209,3 +226,125 @@ func NewProviderClientForStorageClient(ctx context.Context, sc *v1alpha1.Storage
209226 }
210227 return pc , nil
211228}
229+
230+ // getResources gets the resources that were created as part of the OBC provisioning.
231+ // The names of the ConfigMap and Secret are always the same as the OBC name.
232+ // The names of the OB's are of the following format: "obc-<namespace_of_OBC>-<OBC_name>"
233+ func (r * OBCReconciler ) getResources (obc * nbv1.ObjectBucketClaim ) (ob * nbv1.ObjectBucket , cm * corev1.ConfigMap , secret * corev1.Secret , errs []error ) {
234+ obName := fmt .Sprintf ("obc-%s-%s" , obc .Namespace , obc .Name )
235+ ob = & nbv1.ObjectBucket {}
236+ if err := r .Get (r .ctx , types.NamespacedName {Name : obName }, ob ); err != nil {
237+ ob = nil
238+ if ! errors .IsNotFound (err ) {
239+ errs = append (errs , fmt .Errorf ("failed to get OB: %w" , err ))
240+ }
241+ }
242+ cm = & corev1.ConfigMap {}
243+ if err := r .Get (r .ctx , types.NamespacedName {Namespace : obc .Namespace , Name : obc .Name }, cm ); err != nil {
244+ cm = nil
245+ if ! errors .IsNotFound (err ) {
246+ errs = append (errs , fmt .Errorf ("failed to get config map: %w" , err ))
247+ }
248+ }
249+ secret = & corev1.Secret {}
250+ if err := r .Get (r .ctx , types.NamespacedName {Namespace : obc .Namespace , Name : obc .Name }, secret ); err != nil {
251+ secret = nil
252+ if ! errors .IsNotFound (err ) {
253+ errs = append (errs , fmt .Errorf ("failed to get secret: %w" , err ))
254+ }
255+ }
256+ return ob , cm , secret , errs
257+ }
258+
259+ // deleteResources handles the related resurces that were created as part of the OBC provisioning
260+ // Since the secret and configmap's ownerReference is the OBC they will be garbage collected once their finalizers are removed.
261+ // The OB must be explicitly deleted since it is a global resource and cannot have a namespaced ownerReference.
262+ func (r * OBCReconciler ) deleteResources (ob * nbv1.ObjectBucket , cm * corev1.ConfigMap , secret * corev1.Secret , obc * nbv1.ObjectBucketClaim ) (err error ) {
263+
264+ if delErr := r .releaseAndDeleteOB (ob ); delErr != nil {
265+ r .log .Error (delErr , "error deleting OB" , ob .Name )
266+ err = delErr
267+ }
268+ if delErr := r .releaseObcSecret (secret ); delErr != nil {
269+ r .log .Error (delErr , "error releasing secret" )
270+ err = delErr
271+ }
272+ if delErr := r .releaseObcConfigMap (cm ); delErr != nil {
273+ r .log .Error (delErr , "error releasing configMap" )
274+ err = delErr
275+ }
276+ return err
277+ }
278+
279+ // The OB does not have an ownerReference and must be explicitly deleted after its finalizer is removed.
280+ func (r * OBCReconciler ) releaseAndDeleteOB (ob * nbv1.ObjectBucket ) error {
281+ if ob == nil {
282+ r .log .Info ("got nil OB, skipping" )
283+ return nil
284+ }
285+
286+ if controllerutil .RemoveFinalizer (ob , nbv1 .ObjectBucketFinalizer ) {
287+ r .log .Info ("removing finalizer from OB" , "name" , ob .Name )
288+ if err := r .Update (r .ctx , ob ); err != nil {
289+ r .log .Info ("Failed to remove finalizer from OB" , "name" , ob .Name )
290+ return fmt .Errorf ("failed to remove finalizer from OB: %v" , err )
291+ }
292+ }
293+
294+ r .log .Info ("deleting OB" , "name" , ob .Name )
295+ if err := r .Delete (r .ctx , ob ); err != nil {
296+ r .log .Info ("Failed to delete OB" , "name" , ob .Name )
297+ return fmt .Errorf ("failed to delete OB: %v" , err )
298+ }
299+
300+ r .log .Info ("OB deleted" , "name" , ob .Name )
301+ return nil
302+ }
303+
304+ // releaseSecret releases the finalizer from the secret.
305+ // The secret will be garbage collected since its ownerReference refers to the parent OBC.
306+ func (r * OBCReconciler ) releaseObcSecret (secret * corev1.Secret ) (err error ) {
307+ if secret == nil {
308+ r .log .Info ("got nil secret, skipping" )
309+ return nil
310+ }
311+ if err := r .Get (r .ctx , types.NamespacedName {Namespace : secret .Namespace , Name : secret .Name }, secret ); err != nil {
312+ r .log .Info ("Failed to get secret" , "namespaced/name" , client .ObjectKeyFromObject (secret ))
313+ return fmt .Errorf ("failed to get secret: %v" , err )
314+ }
315+
316+ if controllerutil .RemoveFinalizer (secret , nbv1 .ObjectBucketFinalizer ) {
317+ r .log .Info ("removing finalizer from secret" , "name" , secret .Name )
318+ if err := r .Update (r .ctx , secret ); err != nil {
319+ r .log .Info ("Failed to remove finalizer from secret" , "namespaced/name" , client .ObjectKeyFromObject (secret ))
320+ return fmt .Errorf ("failed to remove finalizer from secret: %v" , err )
321+ }
322+ }
323+
324+ r .log .Info ("secret finalizer removed" , "namespaced/name" , client .ObjectKeyFromObject (secret ))
325+ return nil
326+ }
327+
328+ // releaseObcConfigMap releases the finalizer from the configmap.
329+ // The configmap will be garbage collected since its ownerReference refers to the parent OBC.
330+ func (r * OBCReconciler ) releaseObcConfigMap (cm * corev1.ConfigMap ) (err error ) {
331+ if cm == nil {
332+ r .log .Info ("got nil configmap, skipping" )
333+ return nil
334+ }
335+ if err := r .Get (r .ctx , types.NamespacedName {Namespace : cm .Namespace , Name : cm .Name }, cm ); err != nil {
336+ r .log .Info ("Failed to get configmap" , "namespaced/name" , client .ObjectKeyFromObject (cm ))
337+ return fmt .Errorf ("failed to get configmap: %v" , err )
338+ }
339+
340+ if controllerutil .RemoveFinalizer (cm , nbv1 .ObjectBucketFinalizer ) {
341+ r .log .Info ("removing finalizer from configmap" , "name" , cm .Name )
342+ if err := r .Update (r .ctx , cm ); err != nil {
343+ r .log .Info ("Failed to remove finalizer from configmap" , "namespaced/name" , client .ObjectKeyFromObject (cm ))
344+ return fmt .Errorf ("failed to remove finalizer from configmap: %v" , err )
345+ }
346+ }
347+
348+ r .log .Info ("configmap finalizer removed" , "namespaced/name" , client .ObjectKeyFromObject (cm ))
349+ return nil
350+ }
0 commit comments