IAM: Add tracing for legacy stores (#114974)

This commit is contained in:
Mihai Doarna
2025-12-09 13:46:18 -06:00
committed by GitHub
parent b8acfade21
commit b3980eeec8
8 changed files with 106 additions and 20 deletions
+6 -6
View File
@@ -90,11 +90,11 @@ func RegisterAPIService(
builder := &IdentityAccessManagementAPIBuilder{
store: store,
userLegacyStore: user.NewLegacyStore(store, accessClient, enableAuthnMutation),
saLegacyStore: serviceaccount.NewLegacyStore(store, accessClient, enableAuthnMutation),
legacyTeamStore: team.NewLegacyStore(store, legacyAccessClient, enableAuthnMutation),
teamBindingLegacyStore: teambinding.NewLegacyBindingStore(store, enableAuthnMutation),
ssoLegacyStore: sso.NewLegacyStore(ssoService),
userLegacyStore: user.NewLegacyStore(store, accessClient, enableAuthnMutation, tracing),
saLegacyStore: serviceaccount.NewLegacyStore(store, accessClient, enableAuthnMutation, tracing),
legacyTeamStore: team.NewLegacyStore(store, legacyAccessClient, enableAuthnMutation, tracing),
teamBindingLegacyStore: teambinding.NewLegacyBindingStore(store, enableAuthnMutation, tracing),
ssoLegacyStore: sso.NewLegacyStore(ssoService, tracing),
coreRolesStorage: coreRolesStorage,
rolesStorage: rolesStorage,
resourcePermissionsStorage: resourcepermission.ProvideStorageBackend(dbProvider),
@@ -114,7 +114,7 @@ func RegisterAPIService(
dual: dual,
unified: unified,
userSearchClient: resource.NewSearchClient(dualwrite.NewSearchAdapter(dual), iamv0.UserResourceInfo.GroupResource(),
unified, user.NewUserLegacySearchClient(userService), features),
unified, user.NewUserLegacySearchClient(userService, tracing), features),
teamSearch: NewTeamSearchHandler(tracing, dual, team.NewLegacyTeamSearchClient(teamService), unified, features),
}
apiregistration.RegisterAPI(builder)
+16 -2
View File
@@ -5,6 +5,7 @@ import (
"fmt"
"strings"
"go.opentelemetry.io/otel/trace"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -35,14 +36,15 @@ var (
var resource = iamv0alpha1.ServiceAccountResourceInfo
func NewLegacyStore(store legacy.LegacyIdentityStore, ac claims.AccessClient, enableAuthnMutation bool) *LegacyStore {
return &LegacyStore{store, ac, enableAuthnMutation}
func NewLegacyStore(store legacy.LegacyIdentityStore, ac claims.AccessClient, enableAuthnMutation bool, tracer trace.Tracer) *LegacyStore {
return &LegacyStore{store, ac, enableAuthnMutation, tracer}
}
type LegacyStore struct {
store legacy.LegacyIdentityStore
ac claims.AccessClient
enableAuthnMutation bool
tracer trace.Tracer
}
// DeleteCollection implements rest.CollectionDeleter.
@@ -52,6 +54,9 @@ func (s *LegacyStore) DeleteCollection(ctx context.Context, deleteValidation res
// Delete implements rest.GracefulDeleter.
func (s *LegacyStore) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) {
ctx, span := s.tracer.Start(ctx, "serviceaccount.Delete")
defer span.End()
if !s.enableAuthnMutation {
return nil, false, apierrors.NewMethodNotSupported(resource.GroupResource(), "delete")
}
@@ -95,6 +100,9 @@ func (s *LegacyStore) Update(ctx context.Context, name string, objInfo rest.Upda
// Create implements rest.Creater.
func (s *LegacyStore) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
ctx, span := s.tracer.Start(ctx, "serviceaccount.Create")
defer span.End()
if !s.enableAuthnMutation {
return nil, apierrors.NewMethodNotSupported(resource.GroupResource(), "create")
}
@@ -165,6 +173,9 @@ func (s *LegacyStore) ConvertToTable(ctx context.Context, object runtime.Object,
}
func (s *LegacyStore) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) {
ctx, span := s.tracer.Start(ctx, "serviceaccount.List")
defer span.End()
res, err := common.List(
ctx, resource, s.ac, common.PaginationFromListOptions(options),
func(ctx context.Context, ns claims.NamespaceInfo, p common.Pagination) (*common.ListResponse[iamv0alpha1.ServiceAccount], error) {
@@ -228,6 +239,9 @@ func extractPluginNameFromTitle(title string) string {
}
func (s *LegacyStore) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
ctx, span := s.tracer.Start(ctx, "serviceaccount.Get")
defer span.End()
ns, err := request.NamespaceInfoFrom(ctx, true)
if err != nil {
return nil, err
+16 -2
View File
@@ -7,6 +7,7 @@ import (
commonv1 "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"go.opentelemetry.io/otel/trace"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -32,12 +33,13 @@ var (
var resource = iamv0.SSOSettingResourceInfo
func NewLegacyStore(service ssosettings.Service) *LegacyStore {
return &LegacyStore{service}
func NewLegacyStore(service ssosettings.Service, tracer trace.Tracer) *LegacyStore {
return &LegacyStore{service, tracer}
}
type LegacyStore struct {
service ssosettings.Service
tracer trace.Tracer
}
// Destroy implements rest.Storage.
@@ -71,6 +73,9 @@ func (s *LegacyStore) NewList() runtime.Object {
// List implements rest.Lister.
func (s *LegacyStore) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) {
ctx, span := s.tracer.Start(ctx, "sso.List")
defer span.End()
ns, _ := request.NamespaceInfoFrom(ctx, false)
settings, err := s.service.List(ctx)
@@ -88,6 +93,9 @@ func (s *LegacyStore) List(ctx context.Context, options *internalversion.ListOpt
// Get implements rest.Getter.
func (s *LegacyStore) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
ctx, span := s.tracer.Start(ctx, "sso.Get")
defer span.End()
ns, _ := request.NamespaceInfoFrom(ctx, false)
setting, err := s.service.GetForProviderWithRedactedSecrets(ctx, name)
@@ -112,6 +120,9 @@ func (s *LegacyStore) Update(
_ bool,
_ *metav1.UpdateOptions,
) (runtime.Object, bool, error) {
ctx, span := s.tracer.Start(ctx, "sso.Update")
defer span.End()
const created = false
ident, err := identity.GetRequester(ctx)
if err != nil {
@@ -148,6 +159,9 @@ func (s *LegacyStore) Delete(
_ rest.ValidateObjectFunc,
options *metav1.DeleteOptions,
) (runtime.Object, bool, error) {
ctx, span := s.tracer.Start(ctx, "sso.Delete")
defer span.End()
obj, err := s.Get(ctx, name, nil)
if err != nil {
return obj, false, err
+19 -2
View File
@@ -5,6 +5,7 @@ import (
"fmt"
"strconv"
"go.opentelemetry.io/otel/trace"
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -35,14 +36,15 @@ var (
var resource = iamv0alpha1.TeamResourceInfo
func NewLegacyStore(store legacy.LegacyIdentityStore, ac claims.AccessClient, enableAuthnMutation bool) *LegacyStore {
return &LegacyStore{store, ac, enableAuthnMutation}
func NewLegacyStore(store legacy.LegacyIdentityStore, ac claims.AccessClient, enableAuthnMutation bool, tracer trace.Tracer) *LegacyStore {
return &LegacyStore{store, ac, enableAuthnMutation, tracer}
}
type LegacyStore struct {
store legacy.LegacyIdentityStore
ac claims.AccessClient
enableAuthnMutation bool
tracer trace.Tracer
}
func (s *LegacyStore) New() runtime.Object {
@@ -74,6 +76,9 @@ func (s *LegacyStore) DeleteCollection(ctx context.Context, deleteValidation res
// Delete implements rest.GracefulDeleter.
func (s *LegacyStore) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) {
ctx, span := s.tracer.Start(ctx, "team.Delete")
defer span.End()
if !s.enableAuthnMutation {
return nil, false, apierrors.NewMethodNotSupported(resource.GroupResource(), "delete")
}
@@ -112,6 +117,9 @@ func (s *LegacyStore) Delete(ctx context.Context, name string, deleteValidation
// Update implements rest.Updater.
func (s *LegacyStore) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
ctx, span := s.tracer.Start(ctx, "team.Update")
defer span.End()
if !s.enableAuthnMutation {
return nil, false, apierrors.NewMethodNotSupported(resource.GroupResource(), "update")
}
@@ -161,6 +169,9 @@ func (s *LegacyStore) Update(ctx context.Context, name string, objInfo rest.Upda
}
func (s *LegacyStore) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) {
ctx, span := s.tracer.Start(ctx, "team.List")
defer span.End()
res, err := common.List(
ctx, resource, s.ac, common.PaginationFromListOptions(options),
func(ctx context.Context, ns claims.NamespaceInfo, p common.Pagination) (*common.ListResponse[iamv0alpha1.Team], error) {
@@ -197,6 +208,9 @@ func (s *LegacyStore) List(ctx context.Context, options *internalversion.ListOpt
}
func (s *LegacyStore) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
ctx, span := s.tracer.Start(ctx, "team.Get")
defer span.End()
ns, err := request.NamespaceInfoFrom(ctx, true)
if err != nil {
return nil, err
@@ -219,6 +233,9 @@ func (s *LegacyStore) Get(ctx context.Context, name string, options *metav1.GetO
}
func (s *LegacyStore) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
ctx, span := s.tracer.Start(ctx, "team.Create")
defer span.End()
if !s.enableAuthnMutation {
return nil, apierrors.NewMethodNotSupported(resource.GroupResource(), "create")
}
+19 -2
View File
@@ -6,6 +6,7 @@ import (
"strconv"
"time"
"go.opentelemetry.io/otel/trace"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -35,13 +36,14 @@ var (
_ rest.CollectionDeleter = (*LegacyBindingStore)(nil)
)
func NewLegacyBindingStore(store legacy.LegacyIdentityStore, enableAuthnMutation bool) *LegacyBindingStore {
return &LegacyBindingStore{store, enableAuthnMutation}
func NewLegacyBindingStore(store legacy.LegacyIdentityStore, enableAuthnMutation bool, tracer trace.Tracer) *LegacyBindingStore {
return &LegacyBindingStore{store, enableAuthnMutation, tracer}
}
type LegacyBindingStore struct {
store legacy.LegacyIdentityStore
enableAuthnMutation bool
tracer trace.Tracer
}
// Destroy implements rest.Storage.
@@ -73,6 +75,9 @@ func (l *LegacyBindingStore) ConvertToTable(ctx context.Context, object runtime.
}
func (l *LegacyBindingStore) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
ctx, span := l.tracer.Start(ctx, "teambinding.Update")
defer span.End()
if !l.enableAuthnMutation {
return nil, false, apierrors.NewMethodNotSupported(bindingResource.GroupResource(), "update")
}
@@ -125,6 +130,9 @@ func (l *LegacyBindingStore) Update(ctx context.Context, name string, objInfo re
}
func (l *LegacyBindingStore) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) {
ctx, span := l.tracer.Start(ctx, "teambinding.Delete")
defer span.End()
if !l.enableAuthnMutation {
return nil, false, apierrors.NewMethodNotSupported(bindingResource.GroupResource(), "delete")
}
@@ -160,6 +168,9 @@ func (l *LegacyBindingStore) DeleteCollection(ctx context.Context, deleteValidat
}
func (l *LegacyBindingStore) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
ctx, span := l.tracer.Start(ctx, "teambinding.Create")
defer span.End()
if !l.enableAuthnMutation {
return nil, apierrors.NewMethodNotSupported(bindingResource.GroupResource(), "create")
}
@@ -230,6 +241,9 @@ func (l *LegacyBindingStore) Create(ctx context.Context, obj runtime.Object, cre
// Get implements rest.Getter.
func (l *LegacyBindingStore) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
ctx, span := l.tracer.Start(ctx, "teambinding.Get")
defer span.End()
ns, err := request.NamespaceInfoFrom(ctx, true)
if err != nil {
return nil, err
@@ -254,6 +268,9 @@ func (l *LegacyBindingStore) Get(ctx context.Context, name string, options *meta
// List implements rest.Lister.
func (l *LegacyBindingStore) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) {
ctx, span := l.tracer.Start(ctx, "teambinding.List")
defer span.End()
ns, err := request.NamespaceInfoFrom(ctx, true)
if err != nil {
return nil, err
+7 -1
View File
@@ -6,6 +6,7 @@ import (
"log/slog"
"math"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc"
"github.com/grafana/grafana/pkg/apimachinery/identity"
@@ -27,13 +28,15 @@ type UserLegacySearchClient struct {
resourcepb.ResourceIndexClient
userService user.Service
log *slog.Logger
tracer trace.Tracer
}
// NewUserLegacySearchClient creates a new UserLegacySearchClient.
func NewUserLegacySearchClient(userService user.Service) *UserLegacySearchClient {
func NewUserLegacySearchClient(userService user.Service, tracer trace.Tracer) *UserLegacySearchClient {
return &UserLegacySearchClient{
userService: userService,
log: slog.Default().With("logger", "legacy-user-search-client"),
tracer: tracer,
}
}
@@ -41,6 +44,9 @@ func NewUserLegacySearchClient(userService user.Service) *UserLegacySearchClient
// It only supports exact matching for title, login, or email.
// FIXME: This implementation only supports a single field query and will be extended in the future.
func (c *UserLegacySearchClient) Search(ctx context.Context, req *resourcepb.ResourceSearchRequest, _ ...grpc.CallOption) (*resourcepb.ResourceSearchResponse, error) {
ctx, span := c.tracer.Start(ctx, "user.Search")
defer span.End()
signedInUser, err := identity.GetRequester(ctx)
if err != nil {
return nil, err
@@ -8,6 +8,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/user/usertest"
res "github.com/grafana/grafana/pkg/storage/unified/resource"
@@ -17,7 +18,7 @@ import (
func TestUserLegacySearchClient_Search(t *testing.T) {
t.Run("should return error if no query fields are provided", func(t *testing.T) {
mockUserService := usertest.NewMockService(t)
client := NewUserLegacySearchClient(mockUserService)
client := NewUserLegacySearchClient(mockUserService, tracing.NewNoopTracerService())
ctx := identity.WithRequester(context.Background(), &user.SignedInUser{OrgID: 1, UserID: 1})
req := &resourcepb.ResourceSearchRequest{
Options: &resourcepb.ListOptions{
@@ -66,7 +67,7 @@ func TestUserLegacySearchClient_Search(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mockUserService := usertest.NewMockService(t)
client := NewUserLegacySearchClient(mockUserService)
client := NewUserLegacySearchClient(mockUserService, tracing.NewNoopTracerService())
ctx := identity.WithRequester(context.Background(), &user.SignedInUser{OrgID: 1, UserID: 1})
req := &resourcepb.ResourceSearchRequest{
Limit: 10,
@@ -125,7 +126,7 @@ func TestUserLegacySearchClient_Search(t *testing.T) {
t.Run("title should have precedence over login and email", func(t *testing.T) {
mockUserService := usertest.NewMockService(t)
client := NewUserLegacySearchClient(mockUserService)
client := NewUserLegacySearchClient(mockUserService, tracing.NewNoopTracerService())
ctx := identity.WithRequester(context.Background(), &user.SignedInUser{OrgID: 1, UserID: 1})
req := &resourcepb.ResourceSearchRequest{
Options: &resourcepb.ListOptions{
+19 -2
View File
@@ -5,6 +5,7 @@ import (
"fmt"
"time"
"go.opentelemetry.io/otel/trace"
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -36,18 +37,22 @@ var (
var resource = iamv0alpha1.UserResourceInfo
func NewLegacyStore(store legacy.LegacyIdentityStore, ac claims.AccessClient, enableAuthnMutation bool) *LegacyStore {
return &LegacyStore{store, ac, enableAuthnMutation}
func NewLegacyStore(store legacy.LegacyIdentityStore, ac claims.AccessClient, enableAuthnMutation bool, tracer trace.Tracer) *LegacyStore {
return &LegacyStore{store, ac, enableAuthnMutation, tracer}
}
type LegacyStore struct {
store legacy.LegacyIdentityStore
ac claims.AccessClient
enableAuthnMutation bool
tracer trace.Tracer
}
// Update implements rest.Updater.
func (s *LegacyStore) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
ctx, span := s.tracer.Start(ctx, "user.Update")
defer span.End()
if !s.enableAuthnMutation {
return nil, false, apierrors.NewMethodNotSupported(resource.GroupResource(), "update")
}
@@ -105,6 +110,9 @@ func (s *LegacyStore) DeleteCollection(ctx context.Context, deleteValidation res
// Delete implements rest.GracefulDeleter.
func (s *LegacyStore) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) {
ctx, span := s.tracer.Start(ctx, "user.Delete")
defer span.End()
if !s.enableAuthnMutation {
return nil, false, apierrors.NewMethodNotSupported(resource.GroupResource(), "delete")
}
@@ -171,6 +179,9 @@ func (s *LegacyStore) ConvertToTable(ctx context.Context, object runtime.Object,
}
func (s *LegacyStore) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) {
ctx, span := s.tracer.Start(ctx, "user.List")
defer span.End()
res, err := common.List(
ctx, resource, s.ac, common.PaginationFromListOptions(options),
func(ctx context.Context, ns claims.NamespaceInfo, p common.Pagination) (*common.ListResponse[iamv0alpha1.User], error) {
@@ -206,6 +217,9 @@ func (s *LegacyStore) List(ctx context.Context, options *internalversion.ListOpt
}
func (s *LegacyStore) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
ctx, span := s.tracer.Start(ctx, "user.Get")
defer span.End()
ns, err := request.NamespaceInfoFrom(ctx, true)
if err != nil {
return nil, err
@@ -229,6 +243,9 @@ func (s *LegacyStore) Get(ctx context.Context, name string, options *metav1.GetO
// Create implements rest.Creater.
func (s *LegacyStore) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
ctx, span := s.tracer.Start(ctx, "user.Create")
defer span.End()
if !s.enableAuthnMutation {
return nil, apierrors.NewMethodNotSupported(resource.GroupResource(), "create")
}