Skip to content

Commit

Permalink
Add a finaliser to ClusterCatalog
Browse files Browse the repository at this point in the history
New finaliser allows us to remove catalog cache from filesystem
on catalog deletion.

Signed-off-by: Mikalai Radchuk <[email protected]>
  • Loading branch information
Mikalai Radchuk committed Sep 3, 2024
1 parent 60f915e commit a953950
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 14 deletions.
23 changes: 19 additions & 4 deletions cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,10 @@ func main() {
}

clusterExtensionFinalizers := crfinalizer.NewFinalizers()
domain := ocv1alpha1.GroupVersion.Group
cleanupUnpackCacheKey := fmt.Sprintf("%s/cleanup-unpack-cache", domain)
if err := clusterExtensionFinalizers.Register(cleanupUnpackCacheKey, finalizerFunc(func(ctx context.Context, obj client.Object) (crfinalizer.Result, error) {
if err := clusterExtensionFinalizers.Register(controllers.ClusterExtensionCleanupUnpackCacheFinalizer, finalizerFunc(func(ctx context.Context, obj client.Object) (crfinalizer.Result, error) {
return crfinalizer.Result{}, os.RemoveAll(filepath.Join(unpacker.BaseCachePath, obj.GetName()))
})); err != nil {
setupLog.Error(err, "unable to register finalizer", "finalizerKey", cleanupUnpackCacheKey)
setupLog.Error(err, "unable to register finalizer", "finalizerKey", controllers.ClusterExtensionCleanupUnpackCacheFinalizer)
os.Exit(1)
}

Expand Down Expand Up @@ -264,6 +262,23 @@ func main() {
setupLog.Error(err, "unable to create controller", "controller", "ClusterExtension")
os.Exit(1)
}

clusterCatalogFinalizers := crfinalizer.NewFinalizers()
if err := clusterCatalogFinalizers.Register(controllers.ClusterCatalogCacheDeletionFinalizer, finalizerFunc(func(ctx context.Context, obj client.Object) (crfinalizer.Result, error) {
return crfinalizer.Result{}, cacheFetcher.Remove(obj.GetName())
})); err != nil {
setupLog.Error(err, "unable to register finalizer", "finalizerKey", controllers.ClusterCatalogCacheDeletionFinalizer)
os.Exit(1)
}

if err = (&controllers.ClusterCatalogReconciler{
Client: cl,
Finalizers: clusterCatalogFinalizers,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "ClusterExtension")
os.Exit(1)
}

//+kubebuilder:scaffold:builder

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
Expand Down
15 changes: 12 additions & 3 deletions config/base/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,35 @@ rules:
- olm.operatorframework.io
resources:
- catalogmetadata
- clustercatalogs
verbs:
- list
- watch
- apiGroups:
- olm.operatorframework.io
resources:
- clusterextensions
- clustercatalogs
verbs:
- get
- list
- patch
- update
- watch
- apiGroups:
- olm.operatorframework.io
resources:
- clustercatalogs/finalizers
- clusterextensions/finalizers
verbs:
- update
- apiGroups:
- olm.operatorframework.io
resources:
- clusterextensions
verbs:
- get
- list
- patch
- update
- watch
- apiGroups:
- olm.operatorframework.io
resources:
Expand Down
10 changes: 3 additions & 7 deletions internal/catalogmetadata/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,17 +168,13 @@ func (fsc *filesystemCache) FetchCatalogContents(ctx context.Context, catalog *c
}

// Remove deletes cache directory for a given catalog from the filesystem
func (fsc *filesystemCache) Remove(catalog *catalogd.ClusterCatalog) error {
if catalog == nil {
return fmt.Errorf("error: provided catalog must be non-nil")
}

cacheDir := filepath.Join(fsc.cachePath, catalog.Name)
func (fsc *filesystemCache) Remove(catalogName string) error {
cacheDir := filepath.Join(fsc.cachePath, catalogName)

fsc.mutex.Lock()
defer fsc.mutex.Unlock()

if _, exists := fsc.cacheDataByCatalogName[catalog.Name]; !exists {
if _, exists := fsc.cacheDataByCatalogName[catalogName]; !exists {
return nil
}

Expand Down
80 changes: 80 additions & 0 deletions internal/controllers/clustercatalog_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
Copyright 2024.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package controllers

import (
"context"
"errors"
"fmt"

ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
crfinalizer "sigs.k8s.io/controller-runtime/pkg/finalizer"

catalogd "github.com/operator-framework/catalogd/api/core/v1alpha1"
)

const (
ClusterCatalogCacheDeletionFinalizer = "olm.operatorframework.io/cluster-catalog-cache-deletion"
)

// ClusterCatalogReconciler reconciles a ClusterCatalog object
type ClusterCatalogReconciler struct {
client.Client
Finalizers crfinalizer.Finalizers
}

//+kubebuilder:rbac:groups=olm.operatorframework.io,resources=clustercatalogs,verbs=get;list;watch;update
//+kubebuilder:rbac:groups=olm.operatorframework.io,resources=clustercatalogs/finalizers,verbs=update

// The operator controller needs to watch all the bundle objects and reconcile accordingly. Though not ideal, but these permissions are required.
// This has been taken from rukpak, and an issue was created before to discuss it: https://github.com/operator-framework/rukpak/issues/800.
func (r *ClusterCatalogReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
existingCatalog := &catalogd.ClusterCatalog{}
if err := r.Client.Get(ctx, req.NamespacedName, existingCatalog); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}

finalizeResult, err := r.Finalizers.Finalize(ctx, existingCatalog)
if err != nil {
return ctrl.Result{}, err
}

var updateError error
if finalizeResult.StatusUpdated {
if err := r.Client.Status().Update(ctx, existingCatalog); err != nil {
updateError = errors.Join(updateError, fmt.Errorf("error updating status: %v", err))
}
}

if finalizeResult.Updated {
if err := r.Client.Update(ctx, existingCatalog); err != nil {
updateError = errors.Join(updateError, fmt.Errorf("error updating finalizers: %v", err))
}
}

return ctrl.Result{}, updateError
}

// SetupWithManager sets up the controller with the Manager.
func (r *ClusterCatalogReconciler) SetupWithManager(mgr ctrl.Manager) error {
_, err := ctrl.NewControllerManagedBy(mgr).
For(&catalogd.ClusterCatalog{}).
Build(r)

return err
}
4 changes: 4 additions & 0 deletions internal/controllers/clusterextension_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ import (
rukpaksource "github.com/operator-framework/operator-controller/internal/rukpak/source"
)

const (
ClusterExtensionCleanupUnpackCacheFinalizer = "olm.operatorframework.io/cleanup-unpack-cache"
)

// ClusterExtensionReconciler reconciles a ClusterExtension object
type ClusterExtensionReconciler struct {
client.Client
Expand Down

0 comments on commit a953950

Please sign in to comment.