ResourceServer: Add resource server protobuf and wrapper (#90007)
This commit is contained in:
@@ -4,20 +4,23 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
"github.com/spf13/pflag"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/apiserver/pkg/server/options"
|
||||
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
)
|
||||
|
||||
type StorageType string
|
||||
|
||||
const (
|
||||
StorageTypeFile StorageType = "file"
|
||||
StorageTypeEtcd StorageType = "etcd"
|
||||
StorageTypeLegacy StorageType = "legacy"
|
||||
StorageTypeUnified StorageType = "unified"
|
||||
StorageTypeUnifiedGrpc StorageType = "unified-grpc"
|
||||
StorageTypeFile StorageType = "file"
|
||||
StorageTypeEtcd StorageType = "etcd"
|
||||
StorageTypeLegacy StorageType = "legacy"
|
||||
StorageTypeUnified StorageType = "unified"
|
||||
StorageTypeUnifiedGrpc StorageType = "unified-grpc"
|
||||
StorageTypeUnifiedNext StorageType = "unified-next"
|
||||
StorageTypeUnifiedNextGrpc StorageType = "unified-next-grpc"
|
||||
)
|
||||
|
||||
type StorageOptions struct {
|
||||
@@ -43,10 +46,10 @@ func (o *StorageOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
func (o *StorageOptions) Validate() []error {
|
||||
errs := []error{}
|
||||
switch o.StorageType {
|
||||
case StorageTypeFile, StorageTypeEtcd, StorageTypeLegacy, StorageTypeUnified, StorageTypeUnifiedGrpc:
|
||||
case StorageTypeFile, StorageTypeEtcd, StorageTypeLegacy, StorageTypeUnified, StorageTypeUnifiedGrpc, StorageTypeUnifiedNext, StorageTypeUnifiedNextGrpc:
|
||||
// no-op
|
||||
default:
|
||||
errs = append(errs, fmt.Errorf("--grafana-apiserver-storage-type must be one of %s, %s, %s, %s, %s", StorageTypeFile, StorageTypeEtcd, StorageTypeLegacy, StorageTypeUnified, StorageTypeUnifiedGrpc))
|
||||
errs = append(errs, fmt.Errorf("--grafana-apiserver-storage-type must be one of %s, %s, %s, %s, %s, %s, %s", StorageTypeFile, StorageTypeEtcd, StorageTypeLegacy, StorageTypeUnified, StorageTypeUnifiedGrpc, StorageTypeUnifiedNext, StorageTypeUnifiedNextGrpc))
|
||||
}
|
||||
|
||||
if _, _, err := net.SplitHostPort(o.Address); err != nil {
|
||||
|
||||
@@ -4,10 +4,13 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/grafana/dskit/services"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"gocloud.dev/blob/fileblob"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -44,6 +47,9 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/store/entity/db/dbimpl"
|
||||
"github.com/grafana/grafana/pkg/services/store/entity/sqlstash"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/apistore"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/entitybridge"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -199,6 +205,7 @@ func (s *service) RegisterAPI(b builder.APIGroupBuilder) {
|
||||
s.builders = append(s.builders, b)
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (s *service) start(ctx context.Context) error {
|
||||
defer close(s.startedCh)
|
||||
|
||||
@@ -258,39 +265,87 @@ func (s *service) start(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
case grafanaapiserveroptions.StorageTypeUnified:
|
||||
case grafanaapiserveroptions.StorageTypeUnifiedNext:
|
||||
// CDK (for now)
|
||||
dir := filepath.Join(s.cfg.DataPath, "unistore", "resource")
|
||||
if err := os.MkdirAll(dir, 0o750); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bucket, err := fileblob.OpenBucket(dir, &fileblob.Options{
|
||||
CreateDir: true,
|
||||
Metadata: fileblob.MetadataDontWrite, // skip
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
backend, err := resource.NewCDKBackend(context.Background(), resource.CDKBackendOptions{
|
||||
Tracer: s.tracing,
|
||||
Bucket: bucket,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
server, err := resource.NewResourceServer(resource.ResourceServerOptions{Backend: backend})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
serverConfig.Config.RESTOptionsGetter = apistore.NewRESTOptionsGetterForServer(server,
|
||||
o.RecommendedOptions.Etcd.StorageConfig.Codec)
|
||||
|
||||
case grafanaapiserveroptions.StorageTypeUnifiedNextGrpc:
|
||||
if !s.features.IsEnabledGlobally(featuremgmt.FlagUnifiedStorage) {
|
||||
return fmt.Errorf("unified storage requires the unifiedStorage feature flag")
|
||||
}
|
||||
|
||||
eDB, err := dbimpl.ProvideEntityDB(s.db, s.cfg, s.features, s.tracing)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
storeServer, err := sqlstash.ProvideSQLEntityServer(eDB, s.tracing)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
store := entity.NewEntityStoreClientLocal(storeServer)
|
||||
|
||||
serverConfig.Config.RESTOptionsGetter = entitystorage.NewRESTOptionsGetter(s.cfg, store, o.RecommendedOptions.Etcd.StorageConfig.Codec)
|
||||
|
||||
case grafanaapiserveroptions.StorageTypeUnifiedGrpc:
|
||||
// Create a connection to the gRPC server
|
||||
conn, err := grpc.NewClient(o.StorageOptions.Address, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: determine when to close the connection, we cannot defer it here
|
||||
// defer conn.Close()
|
||||
|
||||
// Create a client instance
|
||||
store := entity.NewEntityStoreClientGRPC(conn)
|
||||
client := resource.NewResourceStoreClientGRPC(conn)
|
||||
serverConfig.Config.RESTOptionsGetter = apistore.NewRESTOptionsGetter(client, o.RecommendedOptions.Etcd.StorageConfig.Codec)
|
||||
|
||||
serverConfig.Config.RESTOptionsGetter = entitystorage.NewRESTOptionsGetter(s.cfg, store, o.RecommendedOptions.Etcd.StorageConfig.Codec)
|
||||
case grafanaapiserveroptions.StorageTypeUnified, grafanaapiserveroptions.StorageTypeUnifiedGrpc:
|
||||
var client entity.EntityStoreClient
|
||||
var entityServer sqlstash.SqlEntityServer
|
||||
|
||||
if o.StorageOptions.StorageType == grafanaapiserveroptions.StorageTypeUnifiedGrpc {
|
||||
conn, err := grpc.NewClient(o.StorageOptions.Address, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client = entity.NewEntityStoreClientGRPC(conn)
|
||||
} else {
|
||||
if !s.features.IsEnabledGlobally(featuremgmt.FlagUnifiedStorage) {
|
||||
return fmt.Errorf("unified storage requires the unifiedStorage feature flag")
|
||||
}
|
||||
|
||||
eDB, err := dbimpl.ProvideEntityDB(s.db, s.cfg, s.features, s.tracing)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entityServer, err = sqlstash.ProvideSQLEntityServer(eDB, s.tracing)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client = entity.NewEntityStoreClientLocal(entityServer)
|
||||
}
|
||||
|
||||
if false {
|
||||
// Use the entity bridge
|
||||
server, err := entitybridge.EntityAsResourceServer(client, entityServer, s.tracing)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
serverConfig.Config.RESTOptionsGetter = apistore.NewRESTOptionsGetterForServer(server,
|
||||
o.RecommendedOptions.Etcd.StorageConfig.Codec)
|
||||
} else {
|
||||
serverConfig.Config.RESTOptionsGetter = entitystorage.NewRESTOptionsGetter(s.cfg,
|
||||
client, o.RecommendedOptions.Etcd.StorageConfig.Codec)
|
||||
}
|
||||
|
||||
case grafanaapiserveroptions.StorageTypeLegacy:
|
||||
fallthrough
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc (unknown)
|
||||
// source: entity.proto
|
||||
|
||||
@@ -1401,7 +1401,7 @@ type EntityListRequest struct {
|
||||
WithStatus bool `protobuf:"varint,10,opt,name=with_status,json=withStatus,proto3" json:"with_status,omitempty"`
|
||||
// list deleted entities instead of active ones
|
||||
Deleted bool `protobuf:"varint,12,opt,name=deleted,proto3" json:"deleted,omitempty"`
|
||||
// Limit to a set of origin keys (empty is all)
|
||||
// Deprecated: Limit to a set of origin keys (empty is all)
|
||||
OriginKeys []string `protobuf:"bytes,13,rep,name=origin_keys,json=originKeys,proto3" json:"origin_keys,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc-gen-go-grpc v1.4.0
|
||||
// - protoc (unknown)
|
||||
// source: entity.proto
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
// Requires gRPC-Go v1.62.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion8
|
||||
|
||||
const (
|
||||
EntityStore_Read_FullMethodName = "/entity.EntityStore/Read"
|
||||
@@ -32,6 +32,8 @@ const (
|
||||
// EntityStoreClient is the client API for EntityStore 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.
|
||||
//
|
||||
// The entity store provides a basic CRUD (+watch eventually) interface for generic entities
|
||||
type EntityStoreClient interface {
|
||||
Read(ctx context.Context, in *ReadEntityRequest, opts ...grpc.CallOption) (*Entity, error)
|
||||
Create(ctx context.Context, in *CreateEntityRequest, opts ...grpc.CallOption) (*CreateEntityResponse, error)
|
||||
@@ -52,8 +54,9 @@ func NewEntityStoreClient(cc grpc.ClientConnInterface) EntityStoreClient {
|
||||
}
|
||||
|
||||
func (c *entityStoreClient) Read(ctx context.Context, in *ReadEntityRequest, opts ...grpc.CallOption) (*Entity, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(Entity)
|
||||
err := c.cc.Invoke(ctx, EntityStore_Read_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, EntityStore_Read_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -61,8 +64,9 @@ func (c *entityStoreClient) Read(ctx context.Context, in *ReadEntityRequest, opt
|
||||
}
|
||||
|
||||
func (c *entityStoreClient) Create(ctx context.Context, in *CreateEntityRequest, opts ...grpc.CallOption) (*CreateEntityResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(CreateEntityResponse)
|
||||
err := c.cc.Invoke(ctx, EntityStore_Create_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, EntityStore_Create_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -70,8 +74,9 @@ func (c *entityStoreClient) Create(ctx context.Context, in *CreateEntityRequest,
|
||||
}
|
||||
|
||||
func (c *entityStoreClient) Update(ctx context.Context, in *UpdateEntityRequest, opts ...grpc.CallOption) (*UpdateEntityResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(UpdateEntityResponse)
|
||||
err := c.cc.Invoke(ctx, EntityStore_Update_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, EntityStore_Update_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -79,8 +84,9 @@ func (c *entityStoreClient) Update(ctx context.Context, in *UpdateEntityRequest,
|
||||
}
|
||||
|
||||
func (c *entityStoreClient) Delete(ctx context.Context, in *DeleteEntityRequest, opts ...grpc.CallOption) (*DeleteEntityResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(DeleteEntityResponse)
|
||||
err := c.cc.Invoke(ctx, EntityStore_Delete_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, EntityStore_Delete_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -88,8 +94,9 @@ func (c *entityStoreClient) Delete(ctx context.Context, in *DeleteEntityRequest,
|
||||
}
|
||||
|
||||
func (c *entityStoreClient) History(ctx context.Context, in *EntityHistoryRequest, opts ...grpc.CallOption) (*EntityHistoryResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(EntityHistoryResponse)
|
||||
err := c.cc.Invoke(ctx, EntityStore_History_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, EntityStore_History_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -97,8 +104,9 @@ func (c *entityStoreClient) History(ctx context.Context, in *EntityHistoryReques
|
||||
}
|
||||
|
||||
func (c *entityStoreClient) List(ctx context.Context, in *EntityListRequest, opts ...grpc.CallOption) (*EntityListResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(EntityListResponse)
|
||||
err := c.cc.Invoke(ctx, EntityStore_List_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, EntityStore_List_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -106,11 +114,12 @@ func (c *entityStoreClient) List(ctx context.Context, in *EntityListRequest, opt
|
||||
}
|
||||
|
||||
func (c *entityStoreClient) Watch(ctx context.Context, opts ...grpc.CallOption) (EntityStore_WatchClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &EntityStore_ServiceDesc.Streams[0], EntityStore_Watch_FullMethodName, opts...)
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &EntityStore_ServiceDesc.Streams[0], EntityStore_Watch_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &entityStoreWatchClient{stream}
|
||||
x := &entityStoreWatchClient{ClientStream: stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
@@ -137,8 +146,9 @@ func (x *entityStoreWatchClient) Recv() (*EntityWatchResponse, error) {
|
||||
}
|
||||
|
||||
func (c *entityStoreClient) IsHealthy(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(HealthCheckResponse)
|
||||
err := c.cc.Invoke(ctx, EntityStore_IsHealthy_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, EntityStore_IsHealthy_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -148,6 +158,8 @@ func (c *entityStoreClient) IsHealthy(ctx context.Context, in *HealthCheckReques
|
||||
// EntityStoreServer is the server API for EntityStore service.
|
||||
// All implementations should embed UnimplementedEntityStoreServer
|
||||
// for forward compatibility
|
||||
//
|
||||
// The entity store provides a basic CRUD (+watch eventually) interface for generic entities
|
||||
type EntityStoreServer interface {
|
||||
Read(context.Context, *ReadEntityRequest) (*Entity, error)
|
||||
Create(context.Context, *CreateEntityRequest) (*CreateEntityResponse, error)
|
||||
@@ -308,7 +320,7 @@ func _EntityStore_List_Handler(srv interface{}, ctx context.Context, dec func(in
|
||||
}
|
||||
|
||||
func _EntityStore_Watch_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(EntityStoreServer).Watch(&entityStoreWatchServer{stream})
|
||||
return srv.(EntityStoreServer).Watch(&entityStoreWatchServer{ServerStream: stream})
|
||||
}
|
||||
|
||||
type EntityStore_WatchServer interface {
|
||||
|
||||
@@ -655,6 +655,7 @@ func (s *sqlEntityServer) List(ctx context.Context, r *entity.EntityListRequest)
|
||||
rvSubQuery.AddWhere("("+strings.Join(where, " OR ")+")", args...)
|
||||
}
|
||||
|
||||
// nolint:staticcheck
|
||||
if len(r.OriginKeys) > 0 {
|
||||
entityQuery.AddWhereIn("origin_key", ToAnyList(r.OriginKeys))
|
||||
rvMaxQuery.AddWhereIn("origin_key", ToAnyList(r.OriginKeys))
|
||||
|
||||
Reference in New Issue
Block a user