IAM Folder Reconciler - revert fetching latest folder info from the folder to improve perf (#111779)

This commit is contained in:
Mihai Turdean
2025-09-30 16:59:06 +00:00
committed by GitHub
parent 98ef07bcb0
commit 7be0c100b6
14 changed files with 100 additions and 447 deletions
-1
View File
@@ -79,7 +79,6 @@ func New(cfg app.Config) (app.App, error) {
folderReconciler, err := reconcilers.NewFolderReconciler(reconcilers.ReconcilerConfig{
ZanzanaCfg: appSpecificConfig.ZanzanaClientCfg,
KubeConfig: &cfg.KubeConfig,
Metrics: metrics,
})
if err != nil {
+21 -12
View File
@@ -8,19 +8,14 @@ import (
"github.com/grafana/grafana-app-sdk/logging"
"github.com/grafana/grafana-app-sdk/operator"
foldersKind "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
"github.com/grafana/grafana/pkg/apimachinery/utils"
"github.com/grafana/grafana/pkg/services/authz"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
"k8s.io/client-go/rest"
)
// FolderStore interface for retrieving folder information
type FolderStore interface {
GetFolderParent(ctx context.Context, namespace, uid string) (string, error)
}
// PermissionStore interface for managing folder permissions
type PermissionStore interface {
GetFolderParents(ctx context.Context, namespace, folderUID string) ([]string, error)
@@ -31,13 +26,11 @@ type PermissionStore interface {
// ReconcilerConfig represents the app-specific configuration
type ReconcilerConfig struct {
ZanzanaCfg authz.ZanzanaClientConfig
KubeConfig *rest.Config
Metrics *ReconcilerMetrics
}
type FolderReconciler struct {
permissionStore PermissionStore
folderStore FolderStore
metrics *ReconcilerMetrics
}
@@ -50,12 +43,10 @@ func NewFolderReconciler(cfg ReconcilerConfig) (operator.Reconciler, error) {
}
// Create dependencies
folderStore := NewAPIFolderStore(cfg.KubeConfig)
permissionStore := NewZanzanaPermissionStore(zanzanaClient)
folderReconciler := &FolderReconciler{
permissionStore: permissionStore,
folderStore: folderStore,
metrics: cfg.Metrics,
}
@@ -137,11 +128,11 @@ func (r *FolderReconciler) handleUpdateFolder(ctx context.Context, folder *folde
folderUID := folder.Name
namespace := folder.Namespace
parentUID, err := r.folderStore.GetFolderParent(ctx, namespace, folderUID)
parentUID, err := getFolderParent(ctx, folder)
if err != nil {
logger.Error("Error getting folder parent", "error", err)
if r.metrics != nil {
r.metrics.RecordReconcileFailure(action, "folder_store")
r.metrics.RecordReconcileFailure(action, "failure_informer")
}
return operator.ReconcileResult{}, err
}
@@ -217,3 +208,21 @@ func validateFolder(folder *foldersKind.Folder) error {
}
return nil
}
func getFolderParent(ctx context.Context, folder *foldersKind.Folder) (string, error) {
tracer := otel.GetTracerProvider().Tracer("iam-folder-reconciler")
_, span := tracer.Start(ctx, "get-folder-parent",
trace.WithAttributes(
attribute.String("folder.uid", folder.Name),
),
)
defer span.End()
folderMeta, err := utils.MetaAccessor(folder)
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, "failed to get folder meta accessor")
return "", err
}
return folderMeta.GetFolder(), nil
}
@@ -1,76 +0,0 @@
package reconcilers
import (
"context"
"fmt"
foldersKind "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
"github.com/grafana/grafana/pkg/apimachinery/utils"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
)
var _ FolderStore = (*APIFolderStore)(nil)
func NewAPIFolderStore(config *rest.Config) FolderStore {
return &APIFolderStore{config}
}
type APIFolderStore struct {
config *rest.Config
}
func (s *APIFolderStore) GetFolderParent(ctx context.Context, namespace, uid string) (string, error) {
tracer := otel.GetTracerProvider().Tracer("iam-folder-reconciler")
ctx, span := tracer.Start(ctx, "APIFolderStore.GetFolderParent",
trace.WithAttributes(
attribute.String("folder.uid", uid),
attribute.String("folder.namespace", namespace),
),
)
defer span.End()
client, err := s.client(namespace)
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, "failed to create kubernetes client")
return "", fmt.Errorf("create resource client: %w", err)
}
// Get the folder by UID
unstructuredObj, err := client.Get(ctx, uid, metav1.GetOptions{})
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, "failed to get folder from kubernetes API")
return "", fmt.Errorf("get folder %s: %w", uid, err)
}
object, err := utils.MetaAccessor(unstructuredObj)
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, "failed to get meta accessor from folder object")
return "", fmt.Errorf("get meta accessor: %w", err)
}
parentUID := object.GetFolder()
span.SetAttributes(attribute.String("folder.parent_uid", parentUID))
span.SetStatus(codes.Ok, "successfully retrieved folder parent")
span.AddEvent("folder.parent.retrieved", trace.WithAttributes(
attribute.String("parent.uid", parentUID),
))
return parentUID, nil
}
func (s *APIFolderStore) client(namespace string) (dynamic.ResourceInterface, error) {
client, err := dynamic.NewForConfig(s.config)
if err != nil {
return nil, err
}
return client.Resource(foldersKind.FolderResourceInfo.GroupVersionResource()).Namespace(namespace), nil
}
-1
View File
@@ -22,7 +22,6 @@ func NewReconcilerMetrics(registerer prometheus.Registerer, namespace string) *R
"success_no_changes_needed",
"failure_informer",
"failure_permission_store",
"failure_folder_store",
"failure_unknown",
},
}