-
Notifications
You must be signed in to change notification settings - Fork 405
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement finalizers for
GrafanaFolder
(#1807)
* feat: Add finalizers to folder cr * chore: Remove controllerLog/syncLog in folder reconciler * chore: Update returned results on errors * chore: Make checks more idiomatic * nit: Improve err accuracy Co-authored-by: Dominik Süß <[email protected]> --------- Co-authored-by: Dominik Süß <[email protected]>
- Loading branch information
1 parent
9bdf1c7
commit ed11c7d
Showing
2 changed files
with
55 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,7 @@ import ( | |
"k8s.io/apimachinery/pkg/runtime" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" | ||
"sigs.k8s.io/controller-runtime/pkg/log" | ||
|
||
grafanav1beta1 "github.com/grafana/grafana-operator/v5/api/v1beta1" | ||
|
@@ -58,17 +59,14 @@ type GrafanaFolderReconciler struct { | |
//+kubebuilder:rbac:groups=grafana.integreatly.org,resources=grafanafolders/finalizers,verbs=update | ||
|
||
func (r *GrafanaFolderReconciler) syncFolders(ctx context.Context) (ctrl.Result, error) { | ||
syncLog := log.FromContext(ctx).WithName("GrafanaFolderReconciler") | ||
foldersSynced := 0 | ||
|
||
// get all grafana instances | ||
grafanas := &grafanav1beta1.GrafanaList{} | ||
var opts []client.ListOption | ||
err := r.Client.List(ctx, grafanas, opts...) | ||
if err != nil { | ||
return ctrl.Result{ | ||
Requeue: true, | ||
}, err | ||
return ctrl.Result{}, err | ||
} | ||
|
||
// no instances, no need to sync | ||
|
@@ -80,9 +78,7 @@ func (r *GrafanaFolderReconciler) syncFolders(ctx context.Context) (ctrl.Result, | |
allFolders := &grafanav1beta1.GrafanaFolderList{} | ||
err = r.Client.List(ctx, allFolders, opts...) | ||
if err != nil { | ||
return ctrl.Result{ | ||
Requeue: true, | ||
}, err | ||
return ctrl.Result{}, err | ||
} | ||
|
||
// sync folders, delete folders from grafana that do no longer have a cr | ||
|
@@ -100,7 +96,7 @@ func (r *GrafanaFolderReconciler) syncFolders(ctx context.Context) (ctrl.Result, | |
for grafana, existingFolders := range foldersToDelete { | ||
grafanaClient, err := client2.NewGeneratedGrafanaClient(ctx, r.Client, grafana) | ||
if err != nil { | ||
return ctrl.Result{Requeue: true}, err | ||
return ctrl.Result{}, err | ||
} | ||
|
||
for _, folder := range existingFolders { | ||
|
@@ -119,9 +115,9 @@ func (r *GrafanaFolderReconciler) syncFolders(ctx context.Context) (ctrl.Result, | |
if err != nil { | ||
var notFound *folders.DeleteFolderNotFound | ||
if errors.As(err, ¬Found) { | ||
syncLog.Info("folder no longer exists", "namespace", namespace, "name", name) | ||
r.Log.Info("folder no longer exists", "namespace", namespace, "name", name) | ||
} else { | ||
return ctrl.Result{Requeue: false}, err | ||
return ctrl.Result{}, err | ||
} | ||
} | ||
|
||
|
@@ -133,12 +129,12 @@ func (r *GrafanaFolderReconciler) syncFolders(ctx context.Context) (ctrl.Result, | |
// so we should minimize those updates | ||
err = r.Client.Status().Update(ctx, grafana) | ||
if err != nil { | ||
return ctrl.Result{Requeue: false}, err | ||
return ctrl.Result{}, err | ||
} | ||
} | ||
|
||
if foldersSynced > 0 { | ||
syncLog.Info("successfully synced folders", "folders", foldersSynced) | ||
r.Log.Info("successfully synced folders", "folders", foldersSynced) | ||
} | ||
return ctrl.Result{Requeue: false}, nil | ||
} | ||
|
@@ -153,8 +149,7 @@ func (r *GrafanaFolderReconciler) syncFolders(ctx context.Context) (ctrl.Result, | |
// For more details, check Reconcile and its Result here: | ||
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile | ||
func (r *GrafanaFolderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { | ||
controllerLog := log.FromContext(ctx).WithName("GrafanaFolderReconciler") | ||
r.Log = controllerLog | ||
r.Log = log.FromContext(ctx).WithName("GrafanaFolderReconciler") | ||
|
||
// periodic sync reconcile | ||
if req.Namespace == "" && req.Name == "" { | ||
|
@@ -166,26 +161,45 @@ func (r *GrafanaFolderReconciler) Reconcile(ctx context.Context, req ctrl.Reques | |
} | ||
|
||
folder := &grafanav1beta1.GrafanaFolder{} | ||
|
||
err := r.Client.Get(ctx, client.ObjectKey{ | ||
Namespace: req.Namespace, | ||
Name: req.Name, | ||
}, folder) | ||
if err != nil { | ||
if kuberr.IsNotFound(err) { | ||
if err := r.onFolderDeleted(ctx, req.Namespace, req.Name); err != nil { | ||
return ctrl.Result{RequeueAfter: RequeueDelay}, err | ||
} | ||
return ctrl.Result{}, nil | ||
} | ||
return ctrl.Result{}, fmt.Errorf("error getting grafana folder cr: %w", err) | ||
} | ||
|
||
if folder.GetDeletionTimestamp() != nil { | ||
// Check if resource needs clean up | ||
if controllerutil.ContainsFinalizer(folder, grafanaFinalizer) { | ||
if err := r.finalize(ctx, folder); err != nil { | ||
return ctrl.Result{}, fmt.Errorf("failed to finalize GrafanaFolder: %w", err) | ||
} | ||
if err := removeFinalizer(ctx, r.Client, folder); err != nil { | ||
return ctrl.Result{}, fmt.Errorf("failed to remove finalizer: %w", err) | ||
} | ||
} | ||
return ctrl.Result{}, nil | ||
} | ||
|
||
defer func() { | ||
folder.Status.Hash = folder.Hash() | ||
folder.Status.LastResync = metav1.Time{Time: time.Now()} | ||
if err := r.Status().Update(ctx, folder); err != nil { | ||
r.Log.Error(err, "updating status") | ||
} | ||
if meta.IsStatusConditionTrue(folder.Status.Conditions, conditionNoMatchingInstance) { | ||
if err := removeFinalizer(ctx, r.Client, folder); err != nil { | ||
r.Log.Error(err, "failed to remove finalizer") | ||
} | ||
} else { | ||
if err := addFinalizer(ctx, r.Client, folder); err != nil { | ||
r.Log.Error(err, "failed to set finalizer") | ||
} | ||
} | ||
}() | ||
|
||
if folder.Spec.ParentFolderUID == folder.CustomUIDOrUID() { | ||
|
@@ -195,18 +209,24 @@ func (r *GrafanaFolderReconciler) Reconcile(ctx context.Context, req ctrl.Reques | |
} | ||
removeInvalidSpec(&folder.Status.Conditions) | ||
|
||
instances, err := GetScopedMatchingInstances(controllerLog, ctx, r.Client, folder) | ||
if err != nil || len(instances) == 0 { | ||
instances, err := GetScopedMatchingInstances(r.Log, ctx, r.Client, folder) | ||
if err != nil { | ||
setNoMatchingInstancesCondition(&folder.Status.Conditions, folder.Generation, err) | ||
meta.RemoveStatusCondition(&folder.Status.Conditions, conditionFolderSynchronized) | ||
folder.Status.NoMatchingInstances = true | ||
return ctrl.Result{}, fmt.Errorf("failed fetching instances: %w", err) | ||
} | ||
|
||
if len(instances) == 0 { | ||
setNoMatchingInstancesCondition(&folder.Status.Conditions, folder.Generation, err) | ||
meta.RemoveStatusCondition(&folder.Status.Conditions, conditionFolderSynchronized) | ||
controllerLog.Error(err, "could not find matching instances", "name", folder.Name, "namespace", folder.Namespace) | ||
folder.Status.NoMatchingInstances = true | ||
return ctrl.Result{RequeueAfter: RequeueDelay}, nil | ||
} | ||
|
||
removeNoMatchingInstance(&folder.Status.Conditions) | ||
folder.Status.NoMatchingInstances = false | ||
controllerLog.Info("found matching Grafana instances for folder", "count", len(instances)) | ||
r.Log.Info("found matching Grafana instances for folder", "count", len(instances)) | ||
|
||
applyErrors := make(map[string]string) | ||
for _, grafana := range instances { | ||
|
@@ -266,7 +286,7 @@ func (r *GrafanaFolderReconciler) SetupWithManager(mgr ctrl.Manager, ctx context | |
return err | ||
} | ||
|
||
func (r *GrafanaFolderReconciler) onFolderDeleted(ctx context.Context, namespace string, name string) error { | ||
func (r *GrafanaFolderReconciler) finalize(ctx context.Context, folder *grafanav1beta1.GrafanaFolder) error { | ||
list := grafanav1beta1.GrafanaList{} | ||
var opts []client.ListOption | ||
err := r.Client.List(ctx, &list, opts...) | ||
|
@@ -276,7 +296,7 @@ func (r *GrafanaFolderReconciler) onFolderDeleted(ctx context.Context, namespace | |
|
||
for _, grafana := range list.Items { | ||
grafana := grafana | ||
if found, uid := grafana.Status.Folders.Find(namespace, name); found { | ||
if found, uid := grafana.Status.Folders.Find(folder.Namespace, folder.Name); found { | ||
grafanaClient, err := client2.NewGeneratedGrafanaClient(ctx, r.Client, &grafana) | ||
if err != nil { | ||
return err | ||
|
@@ -291,7 +311,7 @@ func (r *GrafanaFolderReconciler) onFolderDeleted(ctx context.Context, namespace | |
} | ||
} | ||
|
||
grafana.Status.Folders = grafana.Status.Folders.Remove(namespace, name) | ||
grafana.Status.Folders = grafana.Status.Folders.Remove(folder.Namespace, folder.Name) | ||
err = r.Client.Status().Update(ctx, &grafana) | ||
if err != nil { | ||
return err | ||
|