From 4913baaf0407e44d8ac3c47b1bd17f2a5d927a46 Mon Sep 17 00:00:00 2001 From: mayor Date: Mon, 12 Jan 2026 17:59:46 +0100 Subject: [PATCH] Fix compilation errors from SearchServer extraction - Update NewLocalResourceClient to accept SearchServer parameter - Add SearchClient methods to ResourceClient interface (client needs both) - Fix directResourceClient to implement new interface with stub methods - Update search_and_storage.go test to create SearchServer separately This continues the work of extracting SearchServer from ResourceServer to enable independent usage by storage. Co-Authored-By: Claude Opus 4.5 --- pkg/registry/apis/dashboard/legacy/client.go | 32 ++++++++------- pkg/storage/unified/resource/client.go | 25 ++++++++++- .../unified/testing/search_and_storage.go | 41 ++++++++++++------- 3 files changed, 66 insertions(+), 32 deletions(-) diff --git a/pkg/registry/apis/dashboard/legacy/client.go b/pkg/registry/apis/dashboard/legacy/client.go index 2d5b37b7aec..7ba6346cb52 100644 --- a/pkg/registry/apis/dashboard/legacy/client.go +++ b/pkg/registry/apis/dashboard/legacy/client.go @@ -38,10 +38,10 @@ func (d *directResourceClient) GetBlob(ctx context.Context, in *resourcepb.GetBl return d.server.GetBlob(ctx, in) } -//// GetStats implements ResourceClient. -//func (d *directResourceClient) GetStats(ctx context.Context, in *resourcepb.ResourceStatsRequest, opts ...grpc.CallOption) (*resourcepb.ResourceStatsResponse, error) { -// return d.server.GetStats(ctx, in) -//} +// GetStats implements ResourceClient (SearchClient). +func (d *directResourceClient) GetStats(ctx context.Context, in *resourcepb.ResourceStatsRequest, opts ...grpc.CallOption) (*resourcepb.ResourceStatsResponse, error) { + return nil, fmt.Errorf("GetStats not supported with direct resource client") +} // IsHealthy implements ResourceClient. func (d *directResourceClient) IsHealthy(ctx context.Context, in *resourcepb.HealthCheckRequest, opts ...grpc.CallOption) (*resourcepb.HealthCheckResponse, error) { @@ -53,13 +53,15 @@ func (d *directResourceClient) List(ctx context.Context, in *resourcepb.ListRequ return d.server.List(ctx, in) } -//func (d *directResourceClient) ListManagedObjects(ctx context.Context, in *resourcepb.ListManagedObjectsRequest, opts ...grpc.CallOption) (*resourcepb.ListManagedObjectsResponse, error) { -// return d.server.ListManagedObjects(ctx, in) -//} -// -//func (d *directResourceClient) CountManagedObjects(ctx context.Context, in *resourcepb.CountManagedObjectsRequest, opts ...grpc.CallOption) (*resourcepb.CountManagedObjectsResponse, error) { -// return d.server.CountManagedObjects(ctx, in) -//} +// ListManagedObjects implements ResourceClient (SearchClient). +func (d *directResourceClient) ListManagedObjects(ctx context.Context, in *resourcepb.ListManagedObjectsRequest, opts ...grpc.CallOption) (*resourcepb.ListManagedObjectsResponse, error) { + return nil, fmt.Errorf("ListManagedObjects not supported with direct resource client") +} + +// CountManagedObjects implements ResourceClient (SearchClient). +func (d *directResourceClient) CountManagedObjects(ctx context.Context, in *resourcepb.CountManagedObjectsRequest, opts ...grpc.CallOption) (*resourcepb.CountManagedObjectsResponse, error) { + return nil, fmt.Errorf("CountManagedObjects not supported with direct resource client") +} // PutBlob implements ResourceClient. func (d *directResourceClient) PutBlob(ctx context.Context, in *resourcepb.PutBlobRequest, opts ...grpc.CallOption) (*resourcepb.PutBlobResponse, error) { @@ -71,10 +73,10 @@ func (d *directResourceClient) Read(ctx context.Context, in *resourcepb.ReadRequ return d.server.Read(ctx, in) } -// Search implements ResourceClient. -//func (d *directResourceClient) Search(ctx context.Context, in *resourcepb.ResourceSearchRequest, opts ...grpc.CallOption) (*resourcepb.ResourceSearchResponse, error) { -// return d.server.Search(ctx, in) -//} +// Search implements ResourceClient (SearchClient). +func (d *directResourceClient) Search(ctx context.Context, in *resourcepb.ResourceSearchRequest, opts ...grpc.CallOption) (*resourcepb.ResourceSearchResponse, error) { + return nil, fmt.Errorf("Search not supported with direct resource client") +} // Update implements ResourceClient. func (d *directResourceClient) Update(ctx context.Context, in *resourcepb.UpdateRequest, opts ...grpc.CallOption) (*resourcepb.UpdateResponse, error) { diff --git a/pkg/storage/unified/resource/client.go b/pkg/storage/unified/resource/client.go index 3580016eeb6..ed871e1c29f 100644 --- a/pkg/storage/unified/resource/client.go +++ b/pkg/storage/unified/resource/client.go @@ -43,6 +43,8 @@ type ResourceClient interface { resourcepb.BlobStoreClient resourcepb.DiagnosticsClient resourcepb.QuotasClient + // SearchClient methods are included for convenience - the client typically needs both + SearchClient } // Internal implementation @@ -95,9 +97,10 @@ func NewLegacyResourceClient(channel grpc.ClientConnInterface, indexChannel grpc return newResourceClient(cc, cci) } -func NewLocalResourceClient(server ResourceServer) ResourceClient { +func NewLocalResourceClient(server ResourceServer, searchServer SearchServer) ResourceClient { // scenario: local in-proc channel := &inprocgrpc.Channel{} + indexChannel := &inprocgrpc.Channel{} tracer := otel.Tracer("github.com/grafana/grafana/pkg/storage/unified/resource") grpcAuthInt := grpcutils.NewUnsafeAuthenticator(tracer) @@ -118,13 +121,31 @@ func NewLocalResourceClient(server ResourceServer) ResourceClient { ) } + // Register search services on the index channel if searchServer is provided + if searchServer != nil { + for _, desc := range []*grpc.ServiceDesc{ + &resourcepb.ResourceIndex_ServiceDesc, + &resourcepb.ManagedObjectIndex_ServiceDesc, + } { + indexChannel.RegisterService( + grpchan.InterceptServer( + desc, + grpcAuth.UnaryServerInterceptor(grpcAuthInt), + grpcAuth.StreamServerInterceptor(grpcAuthInt), + ), + searchServer, + ) + } + } + clientInt := authnlib.NewGrpcClientInterceptor( ProvideInProcExchanger(), authnlib.WithClientInterceptorIDTokenExtractor(idTokenExtractor), ) cc := grpchan.InterceptClientConn(channel, clientInt.UnaryClientInterceptor, clientInt.StreamClientInterceptor) - return newResourceClient(cc, cc) + cci := grpchan.InterceptClientConn(indexChannel, clientInt.UnaryClientInterceptor, clientInt.StreamClientInterceptor) + return newResourceClient(cc, cci) } type RemoteResourceClientConfig struct { diff --git a/pkg/storage/unified/testing/search_and_storage.go b/pkg/storage/unified/testing/search_and_storage.go index fa2e438a377..0f12b422031 100644 --- a/pkg/storage/unified/testing/search_and_storage.go +++ b/pkg/storage/unified/testing/search_and_storage.go @@ -32,6 +32,7 @@ func RunTestSearchAndStorage(t *testing.T, ctx context.Context, backend resource nsPrefix := "test-ns" var server resource.ResourceServer + var searchServer resource.SearchServer t.Run("Create initial resources in storage", func(t *testing.T) { initialResources := []struct { @@ -96,25 +97,35 @@ func RunTestSearchAndStorage(t *testing.T, ctx context.Context, backend resource }) t.Run("Create a resource server with both backends", func(t *testing.T) { - // Create a resource server with both backends + // Create search server first var err error - server, err = resource.NewResourceServer(resource.ResourceServerOptions{ - Backend: backend, - Search: resource.SearchOptions{ - Backend: searchBackend, - Resources: &resource.TestDocumentBuilderSupplier{ - GroupsResources: map[string]string{ - "test.grafana.app": "testresources", - }, + searchOpts := resource.SearchOptions{ + Backend: searchBackend, + Resources: &resource.TestDocumentBuilderSupplier{ + GroupsResources: map[string]string{ + "test.grafana.app": "testresources", }, }, + } + searchServer, err = resource.NewSearchServer(searchOpts, backend, nil, nil, nil, nil) + require.NoError(t, err) + require.NotNil(t, searchServer) + + // Initialize the search server + err = searchServer.Init(ctx) + require.NoError(t, err) + + // Create a resource server with the search server + server, err = resource.NewResourceServer(resource.ResourceServerOptions{ + Backend: backend, + Search: searchServer, }) require.NoError(t, err) }) t.Run("Search for initial resources", func(t *testing.T) { // Test 1: Search for initial resources - searchResp, err := server.Search(ctx, &resourcepb.ResourceSearchRequest{ + searchResp, err := searchServer.Search(ctx, &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ Key: &resourcepb.ResourceKey{ Group: "test.grafana.app", @@ -194,7 +205,7 @@ func RunTestSearchAndStorage(t *testing.T, ctx context.Context, backend resource }) t.Run("Search for documents", func(t *testing.T) { - searchResp, err := server.Search(ctx, &resourcepb.ResourceSearchRequest{ + searchResp, err := searchServer.Search(ctx, &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ Key: &resourcepb.ResourceKey{ Group: "test.grafana.app", @@ -212,7 +223,7 @@ func RunTestSearchAndStorage(t *testing.T, ctx context.Context, backend resource }) t.Run("Search with tags", func(t *testing.T) { - searchResp, err := server.Search(ctx, &resourcepb.ResourceSearchRequest{ + searchResp, err := searchServer.Search(ctx, &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ Key: &resourcepb.ResourceKey{ Group: "test.grafana.app", @@ -231,7 +242,7 @@ func RunTestSearchAndStorage(t *testing.T, ctx context.Context, backend resource require.Equal(t, int64(0), searchResp.TotalHits) // this is the correct way of searching by tag - searchResp, err = server.Search(ctx, &resourcepb.ResourceSearchRequest{ + searchResp, err = searchServer.Search(ctx, &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ Key: &resourcepb.ResourceKey{ Group: "test.grafana.app", @@ -253,7 +264,7 @@ func RunTestSearchAndStorage(t *testing.T, ctx context.Context, backend resource }) t.Run("Search with specific tag", func(t *testing.T) { - searchResp, err := server.Search(ctx, &resourcepb.ResourceSearchRequest{ + searchResp, err := searchServer.Search(ctx, &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ Key: &resourcepb.ResourceKey{ Group: "test.grafana.app", @@ -272,7 +283,7 @@ func RunTestSearchAndStorage(t *testing.T, ctx context.Context, backend resource require.Equal(t, int64(0), searchResp.TotalHits) // this is the correct way of searching by tag - searchResp, err = server.Search(ctx, &resourcepb.ResourceSearchRequest{ + searchResp, err = searchServer.Search(ctx, &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ Key: &resourcepb.ResourceKey{ Group: "test.grafana.app",