mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Search: Replace Origin calls with Repository (#98754)
This commit is contained in:
parent
3eace5f7c8
commit
ed39259461
@ -57,9 +57,12 @@ func (d *directResourceClient) List(ctx context.Context, in *resource.ListReques
|
|||||||
return d.server.List(ctx, in)
|
return d.server.List(ctx, in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Origin implements ResourceClient.
|
func (d *directResourceClient) ListRepositoryObjects(ctx context.Context, in *resource.ListRepositoryObjectsRequest, opts ...grpc.CallOption) (*resource.ListRepositoryObjectsResponse, error) {
|
||||||
func (d *directResourceClient) Origin(ctx context.Context, in *resource.OriginRequest, opts ...grpc.CallOption) (*resource.OriginResponse, error) {
|
return d.server.ListRepositoryObjects(ctx, in)
|
||||||
return d.server.Origin(ctx, in)
|
}
|
||||||
|
|
||||||
|
func (d *directResourceClient) CountRepositoryObjects(ctx context.Context, in *resource.CountRepositoryObjectsRequest, opts ...grpc.CallOption) (*resource.CountRepositoryObjectsResponse, error) {
|
||||||
|
return d.server.CountRepositoryObjects(ctx, in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutBlob implements ResourceClient.
|
// PutBlob implements ResourceClient.
|
||||||
|
@ -330,9 +330,12 @@ func (a *dashboardSqlAccess) History(ctx context.Context, req *resource.HistoryR
|
|||||||
return list, err
|
return list, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used for efficient provisioning
|
func (a *dashboardSqlAccess) ListRepositoryObjects(ctx context.Context, req *resource.ListRepositoryObjectsRequest) (*resource.ListRepositoryObjectsResponse, error) {
|
||||||
func (a *dashboardSqlAccess) Origin(context.Context, *resource.OriginRequest) (*resource.OriginResponse, error) {
|
return nil, fmt.Errorf("not implemented")
|
||||||
return nil, fmt.Errorf("not yet (origin)")
|
}
|
||||||
|
|
||||||
|
func (a *dashboardSqlAccess) CountRepositoryObjects(context.Context, *resource.CountRepositoryObjectsRequest) (*resource.CountRepositoryObjectsResponse, error) {
|
||||||
|
return nil, fmt.Errorf("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStats implements ResourceServer.
|
// GetStats implements ResourceServer.
|
||||||
|
@ -8,11 +8,12 @@ import (
|
|||||||
|
|
||||||
"github.com/fullstorydev/grpchan"
|
"github.com/fullstorydev/grpchan"
|
||||||
"github.com/fullstorydev/grpchan/inprocgrpc"
|
"github.com/fullstorydev/grpchan/inprocgrpc"
|
||||||
authnlib "github.com/grafana/authlib/authn"
|
|
||||||
"github.com/grafana/authlib/claims"
|
|
||||||
grpcAuth "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
|
grpcAuth "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
|
||||||
|
authnlib "github.com/grafana/authlib/authn"
|
||||||
|
"github.com/grafana/authlib/claims"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/services/authn/grpcutils"
|
"github.com/grafana/grafana/pkg/services/authn/grpcutils"
|
||||||
grpcUtils "github.com/grafana/grafana/pkg/storage/unified/resource/grpc"
|
grpcUtils "github.com/grafana/grafana/pkg/storage/unified/resource/grpc"
|
||||||
@ -21,6 +22,7 @@ import (
|
|||||||
type ResourceClient interface {
|
type ResourceClient interface {
|
||||||
ResourceStoreClient
|
ResourceStoreClient
|
||||||
ResourceIndexClient
|
ResourceIndexClient
|
||||||
|
RepositoryIndexClient
|
||||||
BlobStoreClient
|
BlobStoreClient
|
||||||
DiagnosticsClient
|
DiagnosticsClient
|
||||||
}
|
}
|
||||||
@ -29,6 +31,7 @@ type ResourceClient interface {
|
|||||||
type resourceClient struct {
|
type resourceClient struct {
|
||||||
ResourceStoreClient
|
ResourceStoreClient
|
||||||
ResourceIndexClient
|
ResourceIndexClient
|
||||||
|
RepositoryIndexClient
|
||||||
BlobStoreClient
|
BlobStoreClient
|
||||||
DiagnosticsClient
|
DiagnosticsClient
|
||||||
}
|
}
|
||||||
@ -38,6 +41,7 @@ func NewLegacyResourceClient(channel *grpc.ClientConn) ResourceClient {
|
|||||||
return &resourceClient{
|
return &resourceClient{
|
||||||
ResourceStoreClient: NewResourceStoreClient(cc),
|
ResourceStoreClient: NewResourceStoreClient(cc),
|
||||||
ResourceIndexClient: NewResourceIndexClient(cc),
|
ResourceIndexClient: NewResourceIndexClient(cc),
|
||||||
|
RepositoryIndexClient: NewRepositoryIndexClient(cc),
|
||||||
BlobStoreClient: NewBlobStoreClient(cc),
|
BlobStoreClient: NewBlobStoreClient(cc),
|
||||||
DiagnosticsClient: NewDiagnosticsClient(cc),
|
DiagnosticsClient: NewDiagnosticsClient(cc),
|
||||||
}
|
}
|
||||||
@ -51,6 +55,7 @@ func NewLocalResourceClient(server ResourceServer) ResourceClient {
|
|||||||
for _, desc := range []*grpc.ServiceDesc{
|
for _, desc := range []*grpc.ServiceDesc{
|
||||||
&ResourceStore_ServiceDesc,
|
&ResourceStore_ServiceDesc,
|
||||||
&ResourceIndex_ServiceDesc,
|
&ResourceIndex_ServiceDesc,
|
||||||
|
&RepositoryIndex_ServiceDesc,
|
||||||
&BlobStore_ServiceDesc,
|
&BlobStore_ServiceDesc,
|
||||||
&Diagnostics_ServiceDesc,
|
&Diagnostics_ServiceDesc,
|
||||||
} {
|
} {
|
||||||
@ -74,6 +79,7 @@ func NewLocalResourceClient(server ResourceServer) ResourceClient {
|
|||||||
return &resourceClient{
|
return &resourceClient{
|
||||||
ResourceStoreClient: NewResourceStoreClient(cc),
|
ResourceStoreClient: NewResourceStoreClient(cc),
|
||||||
ResourceIndexClient: NewResourceIndexClient(cc),
|
ResourceIndexClient: NewResourceIndexClient(cc),
|
||||||
|
RepositoryIndexClient: NewRepositoryIndexClient(cc),
|
||||||
BlobStoreClient: NewBlobStoreClient(cc),
|
BlobStoreClient: NewBlobStoreClient(cc),
|
||||||
DiagnosticsClient: NewDiagnosticsClient(cc),
|
DiagnosticsClient: NewDiagnosticsClient(cc),
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ type IndexableDocument struct {
|
|||||||
References ResourceReferences `json:"reference,omitempty"`
|
References ResourceReferences `json:"reference,omitempty"`
|
||||||
|
|
||||||
// When the resource is managed by an upstream repository
|
// When the resource is managed by an upstream repository
|
||||||
RepoInfo *utils.ResourceRepositoryInfo `json:"repository,omitempty"`
|
RepoInfo *utils.ResourceRepositoryInfo `json:"repo,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *IndexableDocument) Type() string {
|
func (m *IndexableDocument) Type() string {
|
||||||
@ -261,8 +261,11 @@ const SEARCH_FIELD_CREATED = "created"
|
|||||||
const SEARCH_FIELD_CREATED_BY = "createdBy"
|
const SEARCH_FIELD_CREATED_BY = "createdBy"
|
||||||
const SEARCH_FIELD_UPDATED = "updated"
|
const SEARCH_FIELD_UPDATED = "updated"
|
||||||
const SEARCH_FIELD_UPDATED_BY = "updatedBy"
|
const SEARCH_FIELD_UPDATED_BY = "updatedBy"
|
||||||
const SEARCH_FIELD_REPOSITORY = "repository"
|
|
||||||
const SEARCH_FIELD_REPOSITORY_HASH = "repository_hash"
|
const SEARCH_FIELD_REPOSITORY_NAME = "repo.name"
|
||||||
|
const SEARCH_FIELD_REPOSITORY_PATH = "repo.path"
|
||||||
|
const SEARCH_FIELD_REPOSITORY_HASH = "repo.hash"
|
||||||
|
const SEARCH_FIELD_REPOSITORY_TIME = "repo.time"
|
||||||
|
|
||||||
const SEARCH_FIELD_SCORE = "_score" // the match score
|
const SEARCH_FIELD_SCORE = "_score" // the match score
|
||||||
const SEARCH_FIELD_EXPLAIN = "_explain" // score explanation as JSON object
|
const SEARCH_FIELD_EXPLAIN = "_explain" // score explanation as JSON object
|
||||||
|
@ -40,7 +40,7 @@ func TestStandardDocumentBuilder(t *testing.T) {
|
|||||||
"createdBy": "user:ABC",
|
"createdBy": "user:ABC",
|
||||||
"updatedBy": "user:XYZ",
|
"updatedBy": "user:XYZ",
|
||||||
"name": "test1",
|
"name": "test1",
|
||||||
"repository": {
|
"repo": {
|
||||||
"name": "SQL",
|
"name": "SQL",
|
||||||
"path": "15",
|
"path": "15",
|
||||||
"hash": "xyz"
|
"hash": "xyz"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -470,54 +470,76 @@ message HistoryResponse {
|
|||||||
ErrorResult error = 4;
|
ErrorResult error = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message OriginRequest {
|
// List items within a resource type & repository name
|
||||||
|
// Access control is managed above this request
|
||||||
|
message ListRepositoryObjectsRequest {
|
||||||
// Starting from the requested page (other query parameters must match!)
|
// Starting from the requested page (other query parameters must match!)
|
||||||
string next_page_token = 1;
|
string next_page_token = 1;
|
||||||
|
|
||||||
|
// All results exist within this resource namespace+name
|
||||||
|
ResourceKey key = 2;
|
||||||
|
|
||||||
|
// The name of the repository
|
||||||
|
string name = 3;
|
||||||
|
|
||||||
// Maximum number of items to return
|
// Maximum number of items to return
|
||||||
int64 limit = 2;
|
int64 limit = 4;
|
||||||
|
|
||||||
// Resource identifier
|
|
||||||
ResourceKey key = 3;
|
|
||||||
|
|
||||||
// List the deleted values (eg, show trash)
|
|
||||||
string origin = 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message ResourceOriginInfo {
|
message ListRepositoryObjectsResponse {
|
||||||
// The resource
|
message Item {
|
||||||
ResourceKey key = 1;
|
// The resource object key
|
||||||
|
ResourceKey object = 1;
|
||||||
// Size of the full resource body
|
|
||||||
int32 resource_size = 2;
|
|
||||||
|
|
||||||
// Hash for the resource
|
// Hash for the resource
|
||||||
string resource_hash = 3;
|
string path = 2;
|
||||||
|
|
||||||
// The origin name
|
|
||||||
string origin = 4;
|
|
||||||
|
|
||||||
// Path on the origin
|
|
||||||
string path = 5;
|
|
||||||
|
|
||||||
// Verification hash from the origin
|
// Verification hash from the origin
|
||||||
string hash = 6;
|
string hash = 3;
|
||||||
|
|
||||||
// Change time from the origin
|
// Change time from the origin
|
||||||
int64 timestamp = 7;
|
int64 time = 5;
|
||||||
|
|
||||||
|
// Title inside the payload
|
||||||
|
string title = 6;
|
||||||
|
|
||||||
|
// The name of the folder in metadata
|
||||||
|
string folder = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
message OriginResponse {
|
// Item iterator
|
||||||
repeated ResourceOriginInfo items = 1;
|
repeated Item items = 1;
|
||||||
|
|
||||||
// More results exist... pass this in the next request
|
// More results exist... pass this in the next request
|
||||||
string next_page_token = 2;
|
string next_page_token = 2;
|
||||||
|
|
||||||
// ResourceVersion of the list response
|
// Error details
|
||||||
int64 resource_version = 3;
|
ErrorResult error = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the items that exist with
|
||||||
|
message CountRepositoryObjectsRequest {
|
||||||
|
// Namespace (tenant)
|
||||||
|
string namespace = 1;
|
||||||
|
|
||||||
|
// The name of the repository
|
||||||
|
// (eventually empty to count across all repositories)
|
||||||
|
string repository = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the items that exist with
|
||||||
|
message CountRepositoryObjectsResponse {
|
||||||
|
message KindCount {
|
||||||
|
string group = 1;
|
||||||
|
string resource = 2;
|
||||||
|
int64 count = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stats keyed by the repository name
|
||||||
|
map<string,KindCount> stats = 1;
|
||||||
|
|
||||||
// Error details
|
// Error details
|
||||||
ErrorResult error = 4;
|
ErrorResult error = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message HealthCheckRequest {
|
message HealthCheckRequest {
|
||||||
@ -609,7 +631,7 @@ message ResourceTableColumnDefinition {
|
|||||||
// Defines the column type. In k8s, this will resolve into both the type and format fields
|
// Defines the column type. In k8s, this will resolve into both the type and format fields
|
||||||
ColumnType type = 2;
|
ColumnType type = 2;
|
||||||
|
|
||||||
// The value is an arry of given type
|
// The value is an array of given type
|
||||||
bool is_array = 3;
|
bool is_array = 3;
|
||||||
|
|
||||||
// description is a human readable description of this column.
|
// description is a human readable description of this column.
|
||||||
@ -774,9 +796,16 @@ service ResourceIndex {
|
|||||||
|
|
||||||
// Show resource history (and trash)
|
// Show resource history (and trash)
|
||||||
rpc History(HistoryRequest) returns (HistoryResponse);
|
rpc History(HistoryRequest) returns (HistoryResponse);
|
||||||
|
}
|
||||||
|
|
||||||
// Used for efficient provisioning
|
// Query repository info from the search index.
|
||||||
rpc Origin(OriginRequest) returns (OriginResponse);
|
// Results access control is based on access to the repository *not* the items
|
||||||
|
service RepositoryIndex {
|
||||||
|
// Describe how many resources of each type exist within a repository
|
||||||
|
rpc CountRepositoryObjects(CountRepositoryObjectsRequest) returns (CountRepositoryObjectsResponse);
|
||||||
|
|
||||||
|
// List the resources of a specific kind within a repository
|
||||||
|
rpc ListRepositoryObjects(ListRepositoryObjectsRequest) returns (ListRepositoryObjectsResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
service BlobStore {
|
service BlobStore {
|
||||||
|
@ -389,7 +389,6 @@ const (
|
|||||||
ResourceIndex_Search_FullMethodName = "/resource.ResourceIndex/Search"
|
ResourceIndex_Search_FullMethodName = "/resource.ResourceIndex/Search"
|
||||||
ResourceIndex_GetStats_FullMethodName = "/resource.ResourceIndex/GetStats"
|
ResourceIndex_GetStats_FullMethodName = "/resource.ResourceIndex/GetStats"
|
||||||
ResourceIndex_History_FullMethodName = "/resource.ResourceIndex/History"
|
ResourceIndex_History_FullMethodName = "/resource.ResourceIndex/History"
|
||||||
ResourceIndex_Origin_FullMethodName = "/resource.ResourceIndex/Origin"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResourceIndexClient is the client API for ResourceIndex service.
|
// ResourceIndexClient is the client API for ResourceIndex service.
|
||||||
@ -404,8 +403,6 @@ type ResourceIndexClient interface {
|
|||||||
GetStats(ctx context.Context, in *ResourceStatsRequest, opts ...grpc.CallOption) (*ResourceStatsResponse, error)
|
GetStats(ctx context.Context, in *ResourceStatsRequest, opts ...grpc.CallOption) (*ResourceStatsResponse, error)
|
||||||
// Show resource history (and trash)
|
// Show resource history (and trash)
|
||||||
History(ctx context.Context, in *HistoryRequest, opts ...grpc.CallOption) (*HistoryResponse, error)
|
History(ctx context.Context, in *HistoryRequest, opts ...grpc.CallOption) (*HistoryResponse, error)
|
||||||
// Used for efficient provisioning
|
|
||||||
Origin(ctx context.Context, in *OriginRequest, opts ...grpc.CallOption) (*OriginResponse, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type resourceIndexClient struct {
|
type resourceIndexClient struct {
|
||||||
@ -446,16 +443,6 @@ func (c *resourceIndexClient) History(ctx context.Context, in *HistoryRequest, o
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *resourceIndexClient) Origin(ctx context.Context, in *OriginRequest, opts ...grpc.CallOption) (*OriginResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(OriginResponse)
|
|
||||||
err := c.cc.Invoke(ctx, ResourceIndex_Origin_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourceIndexServer is the server API for ResourceIndex service.
|
// ResourceIndexServer is the server API for ResourceIndex service.
|
||||||
// All implementations should embed UnimplementedResourceIndexServer
|
// All implementations should embed UnimplementedResourceIndexServer
|
||||||
// for forward compatibility
|
// for forward compatibility
|
||||||
@ -468,8 +455,6 @@ type ResourceIndexServer interface {
|
|||||||
GetStats(context.Context, *ResourceStatsRequest) (*ResourceStatsResponse, error)
|
GetStats(context.Context, *ResourceStatsRequest) (*ResourceStatsResponse, error)
|
||||||
// Show resource history (and trash)
|
// Show resource history (and trash)
|
||||||
History(context.Context, *HistoryRequest) (*HistoryResponse, error)
|
History(context.Context, *HistoryRequest) (*HistoryResponse, error)
|
||||||
// Used for efficient provisioning
|
|
||||||
Origin(context.Context, *OriginRequest) (*OriginResponse, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnimplementedResourceIndexServer should be embedded to have forward compatible implementations.
|
// UnimplementedResourceIndexServer should be embedded to have forward compatible implementations.
|
||||||
@ -485,9 +470,6 @@ func (UnimplementedResourceIndexServer) GetStats(context.Context, *ResourceStats
|
|||||||
func (UnimplementedResourceIndexServer) History(context.Context, *HistoryRequest) (*HistoryResponse, error) {
|
func (UnimplementedResourceIndexServer) History(context.Context, *HistoryRequest) (*HistoryResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method History not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method History not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedResourceIndexServer) Origin(context.Context, *OriginRequest) (*OriginResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method Origin not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnsafeResourceIndexServer may be embedded to opt out of forward compatibility for this service.
|
// UnsafeResourceIndexServer may be embedded to opt out of forward compatibility for this service.
|
||||||
// Use of this interface is not recommended, as added methods to ResourceIndexServer will
|
// Use of this interface is not recommended, as added methods to ResourceIndexServer will
|
||||||
@ -554,24 +536,6 @@ func _ResourceIndex_History_Handler(srv interface{}, ctx context.Context, dec fu
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _ResourceIndex_Origin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(OriginRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(ResourceIndexServer).Origin(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: ResourceIndex_Origin_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(ResourceIndexServer).Origin(ctx, req.(*OriginRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourceIndex_ServiceDesc is the grpc.ServiceDesc for ResourceIndex service.
|
// ResourceIndex_ServiceDesc is the grpc.ServiceDesc for ResourceIndex service.
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
// and not to be introspected or modified (even as a copy)
|
// and not to be introspected or modified (even as a copy)
|
||||||
@ -591,9 +555,142 @@ var ResourceIndex_ServiceDesc = grpc.ServiceDesc{
|
|||||||
MethodName: "History",
|
MethodName: "History",
|
||||||
Handler: _ResourceIndex_History_Handler,
|
Handler: _ResourceIndex_History_Handler,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "resource.proto",
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
RepositoryIndex_CountRepositoryObjects_FullMethodName = "/resource.RepositoryIndex/CountRepositoryObjects"
|
||||||
|
RepositoryIndex_ListRepositoryObjects_FullMethodName = "/resource.RepositoryIndex/ListRepositoryObjects"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RepositoryIndexClient is the client API for RepositoryIndex service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
|
//
|
||||||
|
// Query repository info from the search index.
|
||||||
|
// Results access control is based on access to the repository *not* the items
|
||||||
|
type RepositoryIndexClient interface {
|
||||||
|
// Describe how many resources of each type exist within a repository
|
||||||
|
CountRepositoryObjects(ctx context.Context, in *CountRepositoryObjectsRequest, opts ...grpc.CallOption) (*CountRepositoryObjectsResponse, error)
|
||||||
|
// List the resources of a specific kind within a repository
|
||||||
|
ListRepositoryObjects(ctx context.Context, in *ListRepositoryObjectsRequest, opts ...grpc.CallOption) (*ListRepositoryObjectsResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type repositoryIndexClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRepositoryIndexClient(cc grpc.ClientConnInterface) RepositoryIndexClient {
|
||||||
|
return &repositoryIndexClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *repositoryIndexClient) CountRepositoryObjects(ctx context.Context, in *CountRepositoryObjectsRequest, opts ...grpc.CallOption) (*CountRepositoryObjectsResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(CountRepositoryObjectsResponse)
|
||||||
|
err := c.cc.Invoke(ctx, RepositoryIndex_CountRepositoryObjects_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *repositoryIndexClient) ListRepositoryObjects(ctx context.Context, in *ListRepositoryObjectsRequest, opts ...grpc.CallOption) (*ListRepositoryObjectsResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(ListRepositoryObjectsResponse)
|
||||||
|
err := c.cc.Invoke(ctx, RepositoryIndex_ListRepositoryObjects_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepositoryIndexServer is the server API for RepositoryIndex service.
|
||||||
|
// All implementations should embed UnimplementedRepositoryIndexServer
|
||||||
|
// for forward compatibility
|
||||||
|
//
|
||||||
|
// Query repository info from the search index.
|
||||||
|
// Results access control is based on access to the repository *not* the items
|
||||||
|
type RepositoryIndexServer interface {
|
||||||
|
// Describe how many resources of each type exist within a repository
|
||||||
|
CountRepositoryObjects(context.Context, *CountRepositoryObjectsRequest) (*CountRepositoryObjectsResponse, error)
|
||||||
|
// List the resources of a specific kind within a repository
|
||||||
|
ListRepositoryObjects(context.Context, *ListRepositoryObjectsRequest) (*ListRepositoryObjectsResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedRepositoryIndexServer should be embedded to have forward compatible implementations.
|
||||||
|
type UnimplementedRepositoryIndexServer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (UnimplementedRepositoryIndexServer) CountRepositoryObjects(context.Context, *CountRepositoryObjectsRequest) (*CountRepositoryObjectsResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method CountRepositoryObjects not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedRepositoryIndexServer) ListRepositoryObjects(context.Context, *ListRepositoryObjectsRequest) (*ListRepositoryObjectsResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method ListRepositoryObjects not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnsafeRepositoryIndexServer may be embedded to opt out of forward compatibility for this service.
|
||||||
|
// Use of this interface is not recommended, as added methods to RepositoryIndexServer will
|
||||||
|
// result in compilation errors.
|
||||||
|
type UnsafeRepositoryIndexServer interface {
|
||||||
|
mustEmbedUnimplementedRepositoryIndexServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterRepositoryIndexServer(s grpc.ServiceRegistrar, srv RepositoryIndexServer) {
|
||||||
|
s.RegisterService(&RepositoryIndex_ServiceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _RepositoryIndex_CountRepositoryObjects_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(CountRepositoryObjectsRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(RepositoryIndexServer).CountRepositoryObjects(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: RepositoryIndex_CountRepositoryObjects_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(RepositoryIndexServer).CountRepositoryObjects(ctx, req.(*CountRepositoryObjectsRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _RepositoryIndex_ListRepositoryObjects_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(ListRepositoryObjectsRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(RepositoryIndexServer).ListRepositoryObjects(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: RepositoryIndex_ListRepositoryObjects_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(RepositoryIndexServer).ListRepositoryObjects(ctx, req.(*ListRepositoryObjectsRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepositoryIndex_ServiceDesc is the grpc.ServiceDesc for RepositoryIndex service.
|
||||||
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
|
// and not to be introspected or modified (even as a copy)
|
||||||
|
var RepositoryIndex_ServiceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "resource.RepositoryIndex",
|
||||||
|
HandlerType: (*RepositoryIndexServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
{
|
{
|
||||||
MethodName: "Origin",
|
MethodName: "CountRepositoryObjects",
|
||||||
Handler: _ResourceIndex_Origin_Handler,
|
Handler: _RepositoryIndex_CountRepositoryObjects_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "ListRepositoryObjects",
|
||||||
|
Handler: _RepositoryIndex_ListRepositoryObjects_Handler,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Streams: []grpc.StreamDesc{},
|
Streams: []grpc.StreamDesc{},
|
||||||
|
@ -43,9 +43,11 @@ type ResourceIndex interface {
|
|||||||
// When working with federated queries, the additional indexes will be passed in explicitly
|
// When working with federated queries, the additional indexes will be passed in explicitly
|
||||||
Search(ctx context.Context, access authz.AccessClient, req *ResourceSearchRequest, federate []ResourceIndex) (*ResourceSearchResponse, error)
|
Search(ctx context.Context, access authz.AccessClient, req *ResourceSearchRequest, federate []ResourceIndex) (*ResourceSearchResponse, error)
|
||||||
|
|
||||||
// Execute an origin query -- access control is not not checked for each item
|
// List within an response
|
||||||
// NOTE: this will likely be used for provisioning, or it will be removed
|
ListRepositoryObjects(ctx context.Context, req *ListRepositoryObjectsRequest) (*ListRepositoryObjectsResponse, error)
|
||||||
Origin(ctx context.Context, req *OriginRequest) (*OriginResponse, error)
|
|
||||||
|
// Counts the values in a repo
|
||||||
|
CountRepositoryObjects(ctx context.Context) (map[string]int64, error)
|
||||||
|
|
||||||
// Get the number of documents in the index
|
// Get the number of documents in the index
|
||||||
DocCount(ctx context.Context, folder string) (int64, error)
|
DocCount(ctx context.Context, folder string) (int64, error)
|
||||||
@ -94,6 +96,7 @@ type searchSupport struct {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
_ ResourceIndexServer = (*searchSupport)(nil)
|
_ ResourceIndexServer = (*searchSupport)(nil)
|
||||||
|
_ RepositoryIndexServer = (*searchSupport)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
func newSearchSupport(opts SearchOptions, storage StorageBackend, access authz.AccessClient, blob BlobSupport, tracer trace.Tracer) (support *searchSupport, err error) {
|
func newSearchSupport(opts SearchOptions, storage StorageBackend, access authz.AccessClient, blob BlobSupport, tracer trace.Tracer) (support *searchSupport, err error) {
|
||||||
@ -131,12 +134,25 @@ func newSearchSupport(opts SearchOptions, storage StorageBackend, access authz.A
|
|||||||
|
|
||||||
// History implements ResourceIndexServer.
|
// History implements ResourceIndexServer.
|
||||||
func (s *searchSupport) History(context.Context, *HistoryRequest) (*HistoryResponse, error) {
|
func (s *searchSupport) History(context.Context, *HistoryRequest) (*HistoryResponse, error) {
|
||||||
return nil, fmt.Errorf("not implemented yet... likely should not be the serarch server")
|
return nil, fmt.Errorf("not implemented yet... likely should not be the search server")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Origin implements ResourceIndexServer.
|
func (s *searchSupport) ListRepositoryObjects(ctx context.Context, req *ListRepositoryObjectsRequest) (*ListRepositoryObjectsResponse, error) {
|
||||||
func (s *searchSupport) Origin(context.Context, *OriginRequest) (*OriginResponse, error) {
|
idx, err := s.getOrCreateIndex(ctx, NamespacedResource{
|
||||||
return nil, fmt.Errorf("TBD.. rename to repository")
|
Group: req.Key.Group,
|
||||||
|
Namespace: req.Key.Namespace,
|
||||||
|
Resource: req.Key.Resource,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return &ListRepositoryObjectsResponse{
|
||||||
|
Error: AsErrorResult(err),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return idx.ListRepositoryObjects(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *searchSupport) CountRepositoryObjects(context.Context, *CountRepositoryObjectsRequest) (*CountRepositoryObjectsResponse, error) {
|
||||||
|
return nil, fmt.Errorf("not implemented yet... requires iterating kinds")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search implements ResourceIndexServer.
|
// Search implements ResourceIndexServer.
|
||||||
|
@ -29,6 +29,7 @@ import (
|
|||||||
type ResourceServer interface {
|
type ResourceServer interface {
|
||||||
ResourceStoreServer
|
ResourceStoreServer
|
||||||
ResourceIndexServer
|
ResourceIndexServer
|
||||||
|
RepositoryIndexServer
|
||||||
BlobStoreServer
|
BlobStoreServer
|
||||||
DiagnosticsServer
|
DiagnosticsServer
|
||||||
}
|
}
|
||||||
@ -1073,9 +1074,12 @@ func (s *server) History(ctx context.Context, req *HistoryRequest) (*HistoryResp
|
|||||||
return s.search.History(ctx, req)
|
return s.search.History(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Origin implements ResourceServer.
|
func (s *server) ListRepositoryObjects(ctx context.Context, req *ListRepositoryObjectsRequest) (*ListRepositoryObjectsResponse, error) {
|
||||||
func (s *server) Origin(ctx context.Context, req *OriginRequest) (*OriginResponse, error) {
|
return s.search.ListRepositoryObjects(ctx, req)
|
||||||
return s.search.Origin(ctx, req)
|
}
|
||||||
|
|
||||||
|
func (s *server) CountRepositoryObjects(ctx context.Context, req *CountRepositoryObjectsRequest) (*CountRepositoryObjectsResponse, error) {
|
||||||
|
return s.search.CountRepositoryObjects(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsHealthy implements ResourceServer.
|
// IsHealthy implements ResourceServer.
|
||||||
|
@ -245,9 +245,108 @@ func (b *bleveIndex) Flush() (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Origin implements resource.DocumentIndex.
|
func (b *bleveIndex) ListRepositoryObjects(ctx context.Context, req *resource.ListRepositoryObjectsRequest) (*resource.ListRepositoryObjectsResponse, error) {
|
||||||
func (b *bleveIndex) Origin(ctx context.Context, req *resource.OriginRequest) (*resource.OriginResponse, error) {
|
if req.NextPageToken != "" {
|
||||||
panic("unimplemented")
|
return nil, fmt.Errorf("next page not implemented yet")
|
||||||
|
}
|
||||||
|
|
||||||
|
size := 1000000000 // big number
|
||||||
|
if req.Limit > 0 {
|
||||||
|
size = int(req.Limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
found, err := b.index.SearchInContext(ctx, &bleve.SearchRequest{
|
||||||
|
Query: &query.TermQuery{
|
||||||
|
Term: req.Name,
|
||||||
|
FieldVal: resource.SEARCH_FIELD_REPOSITORY_NAME,
|
||||||
|
},
|
||||||
|
Fields: []string{
|
||||||
|
resource.SEARCH_FIELD_TITLE,
|
||||||
|
resource.SEARCH_FIELD_FOLDER,
|
||||||
|
resource.SEARCH_FIELD_REPOSITORY_NAME,
|
||||||
|
resource.SEARCH_FIELD_REPOSITORY_PATH,
|
||||||
|
resource.SEARCH_FIELD_REPOSITORY_HASH,
|
||||||
|
resource.SEARCH_FIELD_REPOSITORY_TIME,
|
||||||
|
},
|
||||||
|
Sort: search.SortOrder{
|
||||||
|
&search.SortField{
|
||||||
|
Field: resource.SEARCH_FIELD_REPOSITORY_PATH,
|
||||||
|
Type: search.SortFieldAsString,
|
||||||
|
Desc: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Size: size,
|
||||||
|
From: 0, // TODO! next page token!!!
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
asString := func(v any) string {
|
||||||
|
if v == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
str, ok := v.(string)
|
||||||
|
if ok {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%v", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
asTime := func(v any) int64 {
|
||||||
|
if v == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
intV, ok := v.(int64)
|
||||||
|
if ok {
|
||||||
|
return intV
|
||||||
|
}
|
||||||
|
str, ok := v.(string)
|
||||||
|
if ok {
|
||||||
|
t, _ := time.Parse(time.RFC3339, str)
|
||||||
|
return t.UnixMilli()
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
rsp := &resource.ListRepositoryObjectsResponse{}
|
||||||
|
for _, hit := range found.Hits {
|
||||||
|
item := &resource.ListRepositoryObjectsResponse_Item{
|
||||||
|
Object: &resource.ResourceKey{},
|
||||||
|
Hash: asString(hit.Fields[resource.SEARCH_FIELD_REPOSITORY_HASH]),
|
||||||
|
Path: asString(hit.Fields[resource.SEARCH_FIELD_REPOSITORY_PATH]),
|
||||||
|
Time: asTime(hit.Fields[resource.SEARCH_FIELD_REPOSITORY_TIME]),
|
||||||
|
Title: asString(hit.Fields[resource.SEARCH_FIELD_TITLE]),
|
||||||
|
Folder: asString(hit.Fields[resource.SEARCH_FIELD_FOLDER]),
|
||||||
|
}
|
||||||
|
err := item.Object.ReadSearchID(hit.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rsp.Items = append(rsp.Items, item)
|
||||||
|
}
|
||||||
|
return rsp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *bleveIndex) CountRepositoryObjects(ctx context.Context) (map[string]int64, error) {
|
||||||
|
found, err := b.index.SearchInContext(ctx, &bleve.SearchRequest{
|
||||||
|
Query: bleve.NewMatchAllQuery(),
|
||||||
|
Size: 0,
|
||||||
|
Facets: bleve.FacetsRequest{
|
||||||
|
"count": bleve.NewFacetRequest(resource.SEARCH_FIELD_REPOSITORY_NAME, 1000), // typically less then 5
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rsp := make(map[string]int64)
|
||||||
|
f, ok := found.Facets["count"]
|
||||||
|
if ok && f.Terms != nil {
|
||||||
|
for _, v := range f.Terms.Terms() {
|
||||||
|
rsp[v.Term] = int64(v.Count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rsp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search implements resource.DocumentIndex.
|
// Search implements resource.DocumentIndex.
|
||||||
|
@ -67,17 +67,38 @@ func getBleveDocMappings(_ resource.SearchableDocumentFields) *mapping.DocumentM
|
|||||||
}
|
}
|
||||||
mapper.AddFieldMappingsAt(resource.SEARCH_FIELD_FOLDER, folderMapping)
|
mapper.AddFieldMappingsAt(resource.SEARCH_FIELD_FOLDER, folderMapping)
|
||||||
|
|
||||||
repoMapping := &mapping.FieldMapping{
|
// Repositories
|
||||||
Name: resource.SEARCH_FIELD_REPOSITORY,
|
repo := bleve.NewDocumentStaticMapping()
|
||||||
|
repo.AddFieldMappingsAt("name", &mapping.FieldMapping{
|
||||||
|
Name: "name",
|
||||||
Type: "text",
|
Type: "text",
|
||||||
Analyzer: keyword.Name,
|
Analyzer: keyword.Name,
|
||||||
Store: true,
|
Store: true,
|
||||||
Index: true,
|
Index: true,
|
||||||
IncludeTermVectors: false,
|
IncludeTermVectors: false,
|
||||||
IncludeInAll: true,
|
IncludeInAll: true,
|
||||||
DocValues: true,
|
})
|
||||||
}
|
repo.AddFieldMappingsAt("path", &mapping.FieldMapping{
|
||||||
mapper.AddFieldMappingsAt(resource.SEARCH_FIELD_REPOSITORY, repoMapping)
|
Name: "path",
|
||||||
|
Type: "text",
|
||||||
|
Analyzer: keyword.Name,
|
||||||
|
Store: true,
|
||||||
|
Index: true,
|
||||||
|
IncludeTermVectors: false,
|
||||||
|
IncludeInAll: true,
|
||||||
|
})
|
||||||
|
repo.AddFieldMappingsAt("hash", &mapping.FieldMapping{
|
||||||
|
Name: "hash",
|
||||||
|
Type: "text",
|
||||||
|
Analyzer: keyword.Name,
|
||||||
|
Store: true,
|
||||||
|
Index: true,
|
||||||
|
IncludeTermVectors: false,
|
||||||
|
IncludeInAll: true,
|
||||||
|
})
|
||||||
|
repo.AddFieldMappingsAt("time", mapping.NewDateTimeFieldMapping())
|
||||||
|
|
||||||
|
mapper.AddSubDocumentMapping("repo", repo)
|
||||||
|
|
||||||
labelMapper := bleve.NewDocumentMapping()
|
labelMapper := bleve.NewDocumentMapping()
|
||||||
mapper.AddSubDocumentMapping(resource.SEARCH_FIELD_LABELS, labelMapper)
|
mapper.AddSubDocumentMapping(resource.SEARCH_FIELD_LABELS, labelMapper)
|
||||||
|
@ -29,6 +29,7 @@ func TestDocumentMapping(t *testing.T) {
|
|||||||
Name: "nnn",
|
Name: "nnn",
|
||||||
Path: "ppp",
|
Path: "ppp",
|
||||||
Hash: "hhh",
|
Hash: "hhh",
|
||||||
|
Timestamp: asTimePointer(1234),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,5 +43,5 @@ func TestDocumentMapping(t *testing.T) {
|
|||||||
|
|
||||||
fmt.Printf("DOC: fields %d\n", len(doc.Fields))
|
fmt.Printf("DOC: fields %d\n", len(doc.Fields))
|
||||||
fmt.Printf("DOC: size %d\n", doc.Size())
|
fmt.Printf("DOC: size %d\n", doc.Size())
|
||||||
require.Equal(t, 12, len(doc.Fields))
|
require.Equal(t, 13, len(doc.Fields))
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,11 @@ package search
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -82,6 +84,12 @@ func TestBleveBackend(t *testing.T) {
|
|||||||
utils.LabelKeyDeprecatedInternalID: "10", // nolint:staticcheck
|
utils.LabelKeyDeprecatedInternalID: "10", // nolint:staticcheck
|
||||||
},
|
},
|
||||||
Tags: []string{"aa", "bb"},
|
Tags: []string{"aa", "bb"},
|
||||||
|
RepoInfo: &utils.ResourceRepositoryInfo{
|
||||||
|
Name: "repo-1",
|
||||||
|
Path: "path/to/aaa.json",
|
||||||
|
Hash: "xyz",
|
||||||
|
Timestamp: asTimePointer(1609462800000), // 2021
|
||||||
|
},
|
||||||
})
|
})
|
||||||
_ = index.Write(&resource.IndexableDocument{
|
_ = index.Write(&resource.IndexableDocument{
|
||||||
RV: 2,
|
RV: 2,
|
||||||
@ -105,6 +113,12 @@ func TestBleveBackend(t *testing.T) {
|
|||||||
"region": "east",
|
"region": "east",
|
||||||
utils.LabelKeyDeprecatedInternalID: "11", // nolint:staticcheck
|
utils.LabelKeyDeprecatedInternalID: "11", // nolint:staticcheck
|
||||||
},
|
},
|
||||||
|
RepoInfo: &utils.ResourceRepositoryInfo{
|
||||||
|
Name: "repo-1",
|
||||||
|
Path: "path/to/bbb.json",
|
||||||
|
Hash: "hijk",
|
||||||
|
Timestamp: asTimePointer(1640998800000), // 2022
|
||||||
|
},
|
||||||
})
|
})
|
||||||
_ = index.Write(&resource.IndexableDocument{
|
_ = index.Write(&resource.IndexableDocument{
|
||||||
RV: 3,
|
RV: 3,
|
||||||
@ -119,7 +133,8 @@ func TestBleveBackend(t *testing.T) {
|
|||||||
TitleSort: "ccc (dash)",
|
TitleSort: "ccc (dash)",
|
||||||
Folder: "zzz",
|
Folder: "zzz",
|
||||||
RepoInfo: &utils.ResourceRepositoryInfo{
|
RepoInfo: &utils.ResourceRepositoryInfo{
|
||||||
Name: "r0",
|
Name: "repo2",
|
||||||
|
Path: "path/in/repo2.yaml",
|
||||||
},
|
},
|
||||||
Fields: map[string]any{
|
Fields: map[string]any{
|
||||||
DASHBOARD_LEGACY_ID: 12,
|
DASHBOARD_LEGACY_ID: 12,
|
||||||
@ -201,6 +216,53 @@ func TestBleveBackend(t *testing.T) {
|
|||||||
rsp.Results.Rows[0].Key.Name,
|
rsp.Results.Rows[0].Key.Name,
|
||||||
rsp.Results.Rows[1].Key.Name,
|
rsp.Results.Rows[1].Key.Name,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Now look for repositories
|
||||||
|
found, err := index.ListRepositoryObjects(ctx, &resource.ListRepositoryObjectsRequest{
|
||||||
|
Name: "repo-1",
|
||||||
|
Limit: 100,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
jj, err := json.MarshalIndent(found, "", " ")
|
||||||
|
require.NoError(t, err)
|
||||||
|
fmt.Printf("%s\n", string(jj))
|
||||||
|
require.JSONEq(t, `{
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"object": {
|
||||||
|
"namespace": "ns",
|
||||||
|
"group": "dashboard.grafana.app",
|
||||||
|
"resource": "dashboards",
|
||||||
|
"name": "aaa"
|
||||||
|
},
|
||||||
|
"path": "path/to/aaa.json",
|
||||||
|
"hash": "xyz",
|
||||||
|
"time": 1609462800000,
|
||||||
|
"title": "aaa (dash)",
|
||||||
|
"folder": "xxx"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"object": {
|
||||||
|
"namespace": "ns",
|
||||||
|
"group": "dashboard.grafana.app",
|
||||||
|
"resource": "dashboards",
|
||||||
|
"name": "bbb"
|
||||||
|
},
|
||||||
|
"path": "path/to/bbb.json",
|
||||||
|
"hash": "hijk",
|
||||||
|
"time": 1640998800000,
|
||||||
|
"title": "bbb (dash)",
|
||||||
|
"folder": "xxx"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`, string(jj))
|
||||||
|
|
||||||
|
counts, err := index.CountRepositoryObjects(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, map[string]int64{
|
||||||
|
"repo-1": 2,
|
||||||
|
"repo2": 1,
|
||||||
|
}, counts)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("build folders", func(t *testing.T) {
|
t.Run("build folders", func(t *testing.T) {
|
||||||
@ -222,6 +284,12 @@ func TestBleveBackend(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Title: "zzz (folder)",
|
Title: "zzz (folder)",
|
||||||
TitleSort: "zzz (folder)",
|
TitleSort: "zzz (folder)",
|
||||||
|
RepoInfo: &utils.ResourceRepositoryInfo{
|
||||||
|
Name: "repo-1",
|
||||||
|
Path: "path/to/folder.json",
|
||||||
|
Hash: "xxxx",
|
||||||
|
Timestamp: asTimePointer(300),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
_ = index.Write(&resource.IndexableDocument{
|
_ = index.Write(&resource.IndexableDocument{
|
||||||
RV: 2,
|
RV: 2,
|
||||||
@ -327,3 +395,11 @@ func TestBleveBackend(t *testing.T) {
|
|||||||
}`, string(disp))
|
}`, string(disp))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func asTimePointer(milli int64) *time.Time {
|
||||||
|
if milli > 0 {
|
||||||
|
t := time.UnixMilli(milli)
|
||||||
|
return &t
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
"title_sort": "test-aaa",
|
"title_sort": "test-aaa",
|
||||||
"created": 1730490142000,
|
"created": 1730490142000,
|
||||||
"createdBy": "user:1",
|
"createdBy": "user:1",
|
||||||
"repository": {
|
"repo": {
|
||||||
"name": "SQL"
|
"name": "SQL"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,7 +11,7 @@
|
|||||||
"title_sort": "test-bbb",
|
"title_sort": "test-bbb",
|
||||||
"created": 1730490142000,
|
"created": 1730490142000,
|
||||||
"createdBy": "user:1",
|
"createdBy": "user:1",
|
||||||
"repository": {
|
"repo": {
|
||||||
"name": "SQL"
|
"name": "SQL"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,7 +11,7 @@
|
|||||||
"title_sort": "test aaa",
|
"title_sort": "test aaa",
|
||||||
"created": 1731336353000,
|
"created": 1731336353000,
|
||||||
"createdBy": "user:t000000001",
|
"createdBy": "user:t000000001",
|
||||||
"repository": {
|
"repo": {
|
||||||
"name": "UI",
|
"name": "UI",
|
||||||
"path": "/playlists/new",
|
"path": "/playlists/new",
|
||||||
"hash": "Grafana v11.4.0-pre (c0de407fee)"
|
"hash": "Grafana v11.4.0-pre (c0de407fee)"
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
"title_sort": "test aaa",
|
"title_sort": "test aaa",
|
||||||
"created": 1706690655000,
|
"created": 1706690655000,
|
||||||
"createdBy": "user:abc",
|
"createdBy": "user:abc",
|
||||||
"repository": {
|
"repo": {
|
||||||
"name": "SQL"
|
"name": "SQL"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,7 @@ package sql
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||||
@ -62,14 +63,12 @@ func (b *backend) History(context.Context, *resource.HistoryRequest) (*resource.
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Origin implements resource.ResourceIndexServer.
|
func (b *backend) RepositoryList(ctx context.Context, req *resource.ListRepositoryObjectsRequest) (*resource.ListRepositoryObjectsResponse, error) {
|
||||||
func (b *backend) Origin(context.Context, *resource.OriginRequest) (*resource.OriginResponse, error) {
|
return nil, fmt.Errorf("SQL backend does not implement RepositoryList")
|
||||||
return &resource.OriginResponse{
|
}
|
||||||
Error: &resource.ErrorResult{
|
|
||||||
Code: http.StatusNotImplemented,
|
func (b *backend) RepositoryStats(context.Context, *resource.CountRepositoryObjectsRequest) (*resource.CountRepositoryObjectsResponse, error) {
|
||||||
Message: "SQL backend does not implement Origin",
|
return nil, fmt.Errorf("SQL backend does not implement RepositoryStats")
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search implements resource.ResourceIndexServer.
|
// Search implements resource.ResourceIndexServer.
|
||||||
|
Loading…
Reference in New Issue
Block a user