EntityStore: Rename ObjectStore to EntityStore (part 1) (#59613)

This commit is contained in:
Ryan McKinley 2022-11-30 13:42:42 -08:00 committed by GitHub
parent b0b74337f1
commit 5dc7b01f9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 3330 additions and 3337 deletions

View File

@ -288,7 +288,7 @@ func (hs *HTTPServer) registerRoutes() {
// Allow HTTP access to the object storage feature (dev only for now)
if hs.Features.IsEnabled(featuremgmt.FlagGrpcServer) {
apiRoute.Group("/object", hs.httpObjectStore.RegisterHTTPRoutes)
apiRoute.Group("/object", hs.httpEntityStore.RegisterHTTPRoutes)
}
}

View File

@ -21,7 +21,7 @@ import (
"github.com/grafana/grafana/pkg/services/querylibrary"
"github.com/grafana/grafana/pkg/services/searchV2"
"github.com/grafana/grafana/pkg/services/stats"
"github.com/grafana/grafana/pkg/services/store/object/httpobjectstore"
"github.com/grafana/grafana/pkg/services/store/entity/httpentitystore"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
@ -145,7 +145,7 @@ type HTTPServer struct {
ThumbService thumbs.Service
ExportService export.ExportService
StorageService store.StorageService
httpObjectStore httpobjectstore.HTTPObjectStore
httpEntityStore httpentitystore.HTTPEntityStore
SearchV2HTTPService searchV2.SearchHTTPService
QueryLibraryHTTPService querylibrary.HTTPService
QueryLibraryService querylibrary.Service
@ -234,7 +234,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
pluginsUpdateChecker *updatechecker.PluginsService, searchUsersService searchusers.Service,
dataSourcesService datasources.DataSourceService, queryDataService *query.Service,
ldapGroups ldap.Groups, teamGuardian teamguardian.TeamGuardian, serviceaccountsService serviceaccounts.Service,
authInfoService login.AuthInfoService, storageService store.StorageService, httpObjectStore httpobjectstore.HTTPObjectStore,
authInfoService login.AuthInfoService, storageService store.StorageService, httpEntityStore httpentitystore.HTTPEntityStore,
notificationService *notifications.NotificationService, dashboardService dashboards.DashboardService,
dashboardProvisioningService dashboards.DashboardProvisioningService, folderService folder.Service,
datasourcePermissionsService permissions.DatasourcePermissionsService, alertNotificationService *alerting.AlertNotificationService,
@ -312,7 +312,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
secretsMigrator: secretsMigrator,
secretsPluginMigrator: secretsPluginMigrator,
secretsStore: secretsStore,
httpObjectStore: httpObjectStore,
httpEntityStore: httpEntityStore,
DataSourcesService: dataSourcesService,
searchUsersService: searchUsersService,
ldapGroups: ldapGroups,

View File

@ -117,7 +117,7 @@ import (
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/star/starimpl"
"github.com/grafana/grafana/pkg/services/store"
objectdummyserver "github.com/grafana/grafana/pkg/services/store/object/dummy"
entitystoredummy "github.com/grafana/grafana/pkg/services/store/entity/dummy"
"github.com/grafana/grafana/pkg/services/store/sanitizer"
"github.com/grafana/grafana/pkg/services/tag"
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
@ -326,7 +326,7 @@ var wireSet = wire.NewSet(
teamimpl.ProvideService,
ngmetrics.ProvideServiceForTest,
notifications.MockNotificationService,
objectdummyserver.ProvideFakeObjectServer,
entitystoredummy.ProvideFakeEntityServer,
wire.Bind(new(notifications.TempUserStore), new(*dbtest.FakeDB)),
wire.Bind(new(notifications.Service), new(*notifications.NotificationServiceMock)),
wire.Bind(new(notifications.WebhookSender), new(*notifications.NotificationServiceMock)),

View File

@ -7,7 +7,7 @@ import (
)
// Grafana resource name. See also:
// https://github.com/grafana/grafana/blob/main/pkg/services/store/object/object.proto#L6
// https://github.com/grafana/grafana/blob/main/pkg/services/store/entity/entity.proto#L6
// NOTE: This structure/format is still under active development and is subject to change
type GRN struct {
// TenantID contains the ID of the tenant (in hosted grafana) or

View File

@ -52,17 +52,11 @@ const (
// ExternalEntityReferenceRuntime_Transformer is a "type" under runtime
// UIDs include: joinByField, organize, seriesToColumns, etc
ExternalEntityReferenceRuntime_Transformer = "transformer"
// ObjectStoreScopeEntity is organized in: {kind}/{uid}
ObjectStoreScopeEntity = "entity"
// ObjectStoreScopeDrive is organized in: {uid/with/slash}.{kind}
ObjectStoreScopeDrive = "drive"
)
// ObjectKindInfo describes information needed from the object store
// EntityKindInfo describes information needed from the object store
// All non-raw types will have a schema that can be used to validate
type ObjectKindInfo struct {
type EntityKindInfo struct {
// Unique short id for this kind
ID string `json:"id,omitempty"`
@ -82,10 +76,10 @@ type ObjectKindInfo struct {
MimeType string `json:"mimeType,omitempty"`
}
// ObjectSummary represents common data derived from a raw object bytes.
// EntitySummary represents common data derived from a raw object bytes.
// The values should not depend on system state, and are derived from the raw object.
// This summary is used for a unified search and object listing
type ObjectSummary struct {
type EntitySummary struct {
UID string `json:"uid,omitempty"`
Kind string `json:"kind,omitempty"`
Name string `json:"name,omitempty"`
@ -99,23 +93,23 @@ type ObjectSummary struct {
URL string `json:"URL,omitempty"`
// When errors exist
Error *ObjectErrorInfo `json:"error,omitempty"`
Error *EntityErrorInfo `json:"error,omitempty"`
// Optional field values. The schema will define and document possible values for a given kind
Fields map[string]interface{} `json:"fields,omitempty"`
// eg: panels within dashboard
Nested []*ObjectSummary `json:"nested,omitempty"`
Nested []*EntitySummary `json:"nested,omitempty"`
// Optional references to external things
References []*ObjectExternalReference `json:"references,omitempty"`
References []*EntityExternalReference `json:"references,omitempty"`
// The summary can not be extended
_ interface{}
}
// This will likely get replaced with a more general error framework.
type ObjectErrorInfo struct {
type EntityErrorInfo struct {
// TODO: Match an error code registry?
Code int64 `json:"code,omitempty"`
@ -129,7 +123,7 @@ type ObjectErrorInfo struct {
// Reference to another object outside itself
// This message is derived from the object body and can be used to search for references.
// This does not represent a method to declare a reference to another object.
type ObjectExternalReference struct {
type EntityExternalReference struct {
// datasource (instance), dashboard (instance),
Kind string `json:"kind,omitempty"`
@ -140,6 +134,6 @@ type ObjectExternalReference struct {
UID string `json:"UID,omitempty"`
}
// ObjectSummaryBuilder will read an object, validate it, and return a summary, sanitized payload, or an error
// EntitySummaryBuilder will read an object, validate it, and return a summary, sanitized payload, or an error
// This should not include values that depend on system state, only the raw object
type ObjectSummaryBuilder = func(ctx context.Context, uid string, body []byte) (*ObjectSummary, []byte, error)
type EntitySummaryBuilder = func(ctx context.Context, uid string, body []byte) (*EntitySummary, []byte, error)

View File

@ -30,7 +30,7 @@ import (
"github.com/grafana/grafana/pkg/services/serviceaccounts"
samanager "github.com/grafana/grafana/pkg/services/serviceaccounts/manager"
"github.com/grafana/grafana/pkg/services/store"
"github.com/grafana/grafana/pkg/services/store/object"
"github.com/grafana/grafana/pkg/services/store/entity"
"github.com/grafana/grafana/pkg/services/store/sanitizer"
"github.com/grafana/grafana/pkg/services/thumbs"
"github.com/grafana/grafana/pkg/services/updatechecker"
@ -52,7 +52,7 @@ func ProvideBackgroundServiceRegistry(
_ dashboardsnapshots.Service, _ *alerting.AlertNotificationService,
_ serviceaccounts.Service, _ *guardian.Provider,
_ *plugindashboardsservice.DashboardUpdater, _ *sanitizer.Provider,
_ *grpcserver.HealthService, _ object.ObjectStoreServer, _ *grpcserver.ReflectionService,
_ *grpcserver.HealthService, _ entity.EntityStoreServer, _ *grpcserver.ReflectionService,
) *BackgroundServiceRegistry {
return NewBackgroundServiceRegistry(
httpServer,

View File

@ -126,9 +126,9 @@ import (
"github.com/grafana/grafana/pkg/services/star/starimpl"
"github.com/grafana/grafana/pkg/services/stats/statsimpl"
"github.com/grafana/grafana/pkg/services/store"
"github.com/grafana/grafana/pkg/services/store/entity/httpentitystore"
"github.com/grafana/grafana/pkg/services/store/entity/sqlstash"
"github.com/grafana/grafana/pkg/services/store/kind"
"github.com/grafana/grafana/pkg/services/store/object/httpobjectstore"
"github.com/grafana/grafana/pkg/services/store/object/sqlstash"
"github.com/grafana/grafana/pkg/services/store/resolver"
"github.com/grafana/grafana/pkg/services/store/sanitizer"
"github.com/grafana/grafana/pkg/services/tag"
@ -361,9 +361,9 @@ var wireBasicSet = wire.NewSet(
grpcserver.ProvideReflectionService,
interceptors.ProvideAuthenticator,
kind.ProvideService, // The registry of known kinds
sqlstash.ProvideSQLObjectServer,
resolver.ProvideObjectReferenceResolver,
httpobjectstore.ProvideHTTPObjectStore,
sqlstash.ProvideSQLEntityServer,
resolver.ProvideEntityReferenceResolver,
httpentitystore.ProvideHTTPEntityStore,
teamimpl.ProvideService,
tempuserimpl.ProvideService,
loginattemptimpl.ProvideService,

View File

@ -13,14 +13,14 @@ import (
"github.com/grafana/grafana/pkg/services/playlist"
"github.com/grafana/grafana/pkg/services/sqlstore/session"
"github.com/grafana/grafana/pkg/services/store"
"github.com/grafana/grafana/pkg/services/store/entity"
"github.com/grafana/grafana/pkg/services/store/kind/snapshot"
"github.com/grafana/grafana/pkg/services/store/object"
"github.com/grafana/grafana/pkg/services/user"
)
var _ Job = new(objectStoreJob)
var _ Job = new(entityStoreJob)
type objectStoreJob struct {
type entityStoreJob struct {
logger log.Logger
statusMu sync.Mutex
@ -32,19 +32,19 @@ type objectStoreJob struct {
sess *session.SessionDB
playlistService playlist.Service
store object.ObjectStoreServer
store entity.EntityStoreServer
dashboardsnapshots dashboardsnapshots.Service
}
func startObjectStoreJob(ctx context.Context,
func startEntityStoreJob(ctx context.Context,
cfg ExportConfig,
broadcaster statusBroadcaster,
db db.DB,
playlistService playlist.Service,
store object.ObjectStoreServer,
store entity.EntityStoreServer,
dashboardsnapshots dashboardsnapshots.Service,
) (Job, error) {
job := &objectStoreJob{
job := &entityStoreJob{
logger: log.New("export_to_object_store_job"),
cfg: cfg,
ctx: ctx,
@ -67,11 +67,11 @@ func startObjectStoreJob(ctx context.Context,
return job, nil
}
func (e *objectStoreJob) requestStop() {
func (e *entityStoreJob) requestStop() {
e.stopRequested = true
}
func (e *objectStoreJob) start(ctx context.Context) {
func (e *entityStoreJob) start(ctx context.Context) {
defer func() {
e.logger.Info("Finished dummy export job")
@ -123,8 +123,8 @@ func (e *objectStoreJob) start(ctx context.Context) {
rowUser.UserID = 0 // avoid Uint64Val issue????
}
_, err = e.store.AdminWrite(ctx, &object.AdminWriteObjectRequest{
GRN: &object.GRN{
_, err = e.store.AdminWrite(ctx, &entity.AdminWriteEntityRequest{
GRN: &entity.GRN{
UID: dash.UID,
Kind: models.StandardKindDashboard,
},
@ -136,7 +136,7 @@ func (e *objectStoreJob) start(ctx context.Context) {
CreatedBy: fmt.Sprintf("user:%d", dash.CreatedBy),
Body: dash.Data,
Comment: "(exported from SQL)",
Origin: &object.ObjectOriginInfo{
Origin: &entity.EntityOriginInfo{
Source: "export-from-sql",
},
})
@ -174,8 +174,8 @@ func (e *objectStoreJob) start(ctx context.Context) {
return
}
_, err = e.store.Write(ctx, &object.WriteObjectRequest{
GRN: &object.GRN{
_, err = e.store.Write(ctx, &entity.WriteEntityRequest{
GRN: &entity.GRN{
UID: playlist.Uid,
Kind: models.StandardKindPlaylist,
},
@ -238,8 +238,8 @@ func (e *objectStoreJob) start(ctx context.Context) {
m.Snapshot = b
}
_, err = e.store.Write(ctx, &object.WriteObjectRequest{
GRN: &object.GRN{
_, err = e.store.Write(ctx, &entity.WriteEntityRequest{
GRN: &entity.GRN{
UID: dto.Key,
Kind: models.StandardKindSnapshot,
},
@ -272,7 +272,7 @@ type dashInfo struct {
}
// TODO, paging etc
func (e *objectStoreJob) getDashboards(ctx context.Context) ([]dashInfo, error) {
func (e *entityStoreJob) getDashboards(ctx context.Context) ([]dashInfo, error) {
e.status.Last = "find dashbaords...."
e.broadcaster(e.status)
@ -281,14 +281,14 @@ func (e *objectStoreJob) getDashboards(ctx context.Context) ([]dashInfo, error)
return dash, err
}
func (e *objectStoreJob) getStatus() ExportStatus {
func (e *entityStoreJob) getStatus() ExportStatus {
e.statusMu.Lock()
defer e.statusMu.Unlock()
return e.status
}
func (e *objectStoreJob) getConfig() ExportConfig {
func (e *entityStoreJob) getConfig() ExportConfig {
e.statusMu.Lock()
defer e.statusMu.Unlock()

View File

@ -12,7 +12,6 @@ import (
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/filestorage"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/store/kind/dashboard"
)
@ -31,7 +30,7 @@ func exportDashboards(helper *commitHelper, job *gitExportJob) error {
return err
}
rootDir := path.Join(helper.orgDir, models.ObjectStoreScopeDrive)
rootDir := path.Join(helper.orgDir, "drive")
folderStructure := commitOptions{
when: time.Now(),
comment: "Exported folder structure",

View File

@ -40,7 +40,7 @@ func exportSystemPlaylists(helper *commitHelper, job *gitExportJob) error {
gitcmd.body = append(gitcmd.body, commitBody{
fpath: filepath.Join(
helper.orgDir,
models.ObjectStoreScopeEntity,
"entity",
models.StandardKindPlaylist,
fmt.Sprintf("%s.json", playlist.Uid)),
body: prettyJSON(playlist),

View File

@ -21,7 +21,7 @@ import (
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/playlist"
"github.com/grafana/grafana/pkg/services/store"
"github.com/grafana/grafana/pkg/services/store/object"
"github.com/grafana/grafana/pkg/services/store/entity"
"github.com/grafana/grafana/pkg/setting"
)
@ -159,7 +159,7 @@ type StandardExport struct {
playlistService playlist.Service
orgService org.Service
datasourceService datasources.DataSourceService
store object.ObjectStoreServer
store entity.EntityStoreServer
// updated with mutex
exportJob Job
@ -167,7 +167,7 @@ type StandardExport struct {
func ProvideService(db db.DB, features featuremgmt.FeatureToggles, gl *live.GrafanaLive, cfg *setting.Cfg,
dashboardsnapshotsService dashboardsnapshots.Service, playlistService playlist.Service, orgService org.Service,
datasourceService datasources.DataSourceService, store object.ObjectStoreServer) ExportService {
datasourceService datasources.DataSourceService, store entity.EntityStoreServer) ExportService {
if !features.IsEnabled(featuremgmt.FlagExport) {
return &StubExport{}
}
@ -234,7 +234,7 @@ func (ex *StandardExport) HandleRequestExport(c *models.ReqContext) response.Res
case "dummy":
job, err = startDummyExportJob(cfg, broadcast)
case "objectStore":
job, err = startObjectStoreJob(ctx, cfg, broadcast, ex.db, ex.playlistService, ex.store, ex.dashboardsnapshotsService)
job, err = startEntityStoreJob(ctx, cfg, broadcast, ex.db, ex.playlistService, ex.store, ex.dashboardsnapshotsService)
case "git":
dir := filepath.Join(ex.dataDir, "export_git", fmt.Sprintf("git_%d", time.Now().Unix()))
if err := os.MkdirAll(dir, os.ModePerm); err != nil {

View File

@ -9,7 +9,7 @@ import (
"github.com/grafana/grafana/pkg/services/playlist"
"github.com/grafana/grafana/pkg/services/sqlstore/session"
objectstore "github.com/grafana/grafana/pkg/services/store"
"github.com/grafana/grafana/pkg/services/store/object"
"github.com/grafana/grafana/pkg/services/store/entity"
"github.com/grafana/grafana/pkg/services/user"
)
@ -21,7 +21,7 @@ import (
type objectStoreImpl struct {
sess *session.SessionDB
sqlimpl *Service
objectstore object.ObjectStoreServer
objectstore entity.EntityStoreServer
}
var _ playlist.Service = &objectStoreImpl{}
@ -55,8 +55,8 @@ func (s *objectStoreImpl) sync() {
return
}
body, _ := json.Marshal(dto)
_, _ = s.objectstore.Write(ctx, &object.WriteObjectRequest{
GRN: &object.GRN{
_, _ = s.objectstore.Write(ctx, &entity.WriteEntityRequest{
GRN: &entity.GRN{
TenantId: info.OrgID,
UID: info.UID,
Kind: models.StandardKindPlaylist,
@ -73,8 +73,8 @@ func (s *objectStoreImpl) Create(ctx context.Context, cmd *playlist.CreatePlayli
if err != nil {
return rsp, fmt.Errorf("unable to write playlist to store")
}
_, err = s.objectstore.Write(ctx, &object.WriteObjectRequest{
GRN: &object.GRN{
_, err = s.objectstore.Write(ctx, &entity.WriteEntityRequest{
GRN: &entity.GRN{
Kind: models.StandardKindPlaylist,
UID: rsp.UID,
},
@ -94,8 +94,8 @@ func (s *objectStoreImpl) Update(ctx context.Context, cmd *playlist.UpdatePlayli
if err != nil {
return rsp, fmt.Errorf("unable to write playlist to store")
}
_, err = s.objectstore.Write(ctx, &object.WriteObjectRequest{
GRN: &object.GRN{
_, err = s.objectstore.Write(ctx, &entity.WriteEntityRequest{
GRN: &entity.GRN{
UID: rsp.Uid,
Kind: models.StandardKindPlaylist,
},
@ -111,8 +111,8 @@ func (s *objectStoreImpl) Update(ctx context.Context, cmd *playlist.UpdatePlayli
func (s *objectStoreImpl) Delete(ctx context.Context, cmd *playlist.DeletePlaylistCommand) error {
err := s.sqlimpl.store.Delete(ctx, cmd)
if err == nil {
_, err = s.objectstore.Delete(ctx, &object.DeleteObjectRequest{
GRN: &object.GRN{
_, err = s.objectstore.Delete(ctx, &entity.DeleteEntityRequest{
GRN: &entity.GRN{
UID: cmd.UID,
Kind: models.StandardKindPlaylist,
},
@ -142,8 +142,8 @@ func (s *objectStoreImpl) GetWithoutItems(ctx context.Context, q *playlist.GetPl
}
func (s *objectStoreImpl) Get(ctx context.Context, q *playlist.GetPlaylistByUidQuery) (*playlist.PlaylistDTO, error) {
rsp, err := s.objectstore.Read(ctx, &object.ReadObjectRequest{
GRN: &object.GRN{
rsp, err := s.objectstore.Read(ctx, &entity.ReadEntityRequest{
GRN: &entity.GRN{
UID: q.UID,
Kind: models.StandardKindPlaylist,
},
@ -152,20 +152,20 @@ func (s *objectStoreImpl) Get(ctx context.Context, q *playlist.GetPlaylistByUidQ
if err != nil {
return nil, err
}
if rsp.Object == nil || rsp.Object.Body == nil {
if rsp.Entity == nil || rsp.Entity.Body == nil {
return nil, fmt.Errorf("missing object")
}
// Get the object from payload
found := &playlist.PlaylistDTO{}
err = json.Unmarshal(rsp.Object.Body, found)
err = json.Unmarshal(rsp.Entity.Body, found)
return found, err
}
func (s *objectStoreImpl) Search(ctx context.Context, q *playlist.GetPlaylistsQuery) (playlist.Playlists, error) {
playlists := make(playlist.Playlists, 0)
rsp, err := s.objectstore.Search(ctx, &object.ObjectSearchRequest{
rsp, err := s.objectstore.Search(ctx, &entity.EntitySearchRequest{
Kind: []string{models.StandardKindPlaylist},
WithBody: true,
Limit: 1000,

View File

@ -6,7 +6,7 @@ import (
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/playlist"
"github.com/grafana/grafana/pkg/services/store/object"
"github.com/grafana/grafana/pkg/services/store/entity"
)
type Service struct {
@ -15,7 +15,7 @@ type Service struct {
var _ playlist.Service = &Service{}
func ProvideService(db db.DB, toggles featuremgmt.FeatureToggles, objserver object.ObjectStoreServer) playlist.Service {
func ProvideService(db db.DB, toggles featuremgmt.FeatureToggles, objserver entity.EntityStoreServer) playlist.Service {
var sqlstore store
// 🐢🐢🐢 pick the store

View File

@ -54,7 +54,7 @@ type dashboard struct {
updated time.Time
// Use generic structure
summary *models.ObjectSummary
summary *models.EntitySummary
}
// buildSignal is sent when search index is accessed in organization for which
@ -913,7 +913,7 @@ func (l sqlDashboardLoader) LoadDashboards(ctx context.Context, orgID int64, das
slug: "",
created: time.Now(),
updated: time.Now(),
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
//ID: 0,
Name: "General",
},

View File

@ -113,14 +113,14 @@ var testDashboards = []dashboard{
{
id: 1,
uid: "1",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "test",
},
},
{
id: 2,
uid: "2",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "boom",
},
},
@ -162,7 +162,7 @@ func TestDashboardIndexUpdates(t *testing.T) {
err := index.updateDashboard(context.Background(), testOrgID, orgIdx, dashboard{
id: 3,
uid: "3",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "created",
},
})
@ -181,7 +181,7 @@ func TestDashboardIndexUpdates(t *testing.T) {
err := index.updateDashboard(context.Background(), testOrgID, orgIdx, dashboard{
id: 2,
uid: "2",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "nginx",
},
})
@ -197,14 +197,14 @@ var testSortDashboards = []dashboard{
{
id: 1,
uid: "1",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "a-test",
},
},
{
id: 2,
uid: "2",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "z-test",
},
},
@ -288,14 +288,14 @@ var testPrefixDashboards = []dashboard{
{
id: 1,
uid: "1",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "Archer Data System",
},
},
{
id: 2,
uid: "2",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "Document Sync repo",
},
},
@ -366,7 +366,7 @@ var longPrefixDashboards = []dashboard{
{
id: 1,
uid: "1",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "Eyjafjallajökull Eruption data",
},
},
@ -385,14 +385,14 @@ var scatteredTokensDashboards = []dashboard{
{
id: 1,
uid: "1",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "Three can keep a secret, if two of them are dead (Benjamin Franklin)",
},
},
{
id: 3,
uid: "2",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "A secret is powerful when it is empty (Umberto Eco)",
},
},
@ -418,7 +418,7 @@ var dashboardsWithFolders = []dashboard{
id: 1,
uid: "1",
isFolder: true,
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "My folder",
},
},
@ -426,9 +426,9 @@ var dashboardsWithFolders = []dashboard{
id: 2,
uid: "2",
folderID: 1,
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "Dashboard in folder 1",
Nested: []*models.ObjectSummary{
Nested: []*models.EntitySummary{
newNestedPanel(1, "Panel 1"),
newNestedPanel(2, "Panel 2"),
},
@ -438,9 +438,9 @@ var dashboardsWithFolders = []dashboard{
id: 3,
uid: "3",
folderID: 1,
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "Dashboard in folder 2",
Nested: []*models.ObjectSummary{
Nested: []*models.EntitySummary{
newNestedPanel(3, "Panel 3"),
},
},
@ -448,9 +448,9 @@ var dashboardsWithFolders = []dashboard{
{
id: 4,
uid: "4",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "One more dash",
Nested: []*models.ObjectSummary{
Nested: []*models.EntitySummary{
newNestedPanel(4, "Panel 4"),
},
},
@ -505,9 +505,9 @@ var dashboardsWithPanels = []dashboard{
{
id: 1,
uid: "1",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "My Dash",
Nested: []*models.ObjectSummary{
Nested: []*models.EntitySummary{
newNestedPanel(1, "Panel 1"),
newNestedPanel(2, "Panel 2"),
},
@ -515,8 +515,8 @@ var dashboardsWithPanels = []dashboard{
},
}
func newNestedPanel(id int64, name string) *models.ObjectSummary {
summary := &models.ObjectSummary{
func newNestedPanel(id int64, name string) *models.EntitySummary {
summary := &models.EntitySummary{
Kind: "panel",
UID: fmt.Sprintf("???#%d", id),
}
@ -553,14 +553,14 @@ var punctuationSplitNgramDashboards = []dashboard{
{
id: 1,
uid: "1",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "heat-torkel",
},
},
{
id: 2,
uid: "2",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "topology heatmap",
},
},
@ -586,7 +586,7 @@ var camelCaseNgramDashboards = []dashboard{
{
id: 1,
uid: "1",
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: "heatTorkel",
},
},
@ -608,7 +608,7 @@ func dashboardsWithTitles(names ...string) []dashboard {
out = append(out, dashboard{
id: no,
uid: fmt.Sprintf("%d", no),
summary: &models.ObjectSummary{
summary: &models.EntitySummary{
Name: name,
},
})

View File

@ -1,4 +1,4 @@
package objectdummyserver
package dummy
import (
"context"
@ -14,59 +14,59 @@ import (
"github.com/grafana/grafana/pkg/infra/x/persistentcollection"
"github.com/grafana/grafana/pkg/services/grpcserver"
"github.com/grafana/grafana/pkg/services/store"
"github.com/grafana/grafana/pkg/services/store/entity"
"github.com/grafana/grafana/pkg/services/store/kind"
"github.com/grafana/grafana/pkg/services/store/object"
"github.com/grafana/grafana/pkg/setting"
)
type ObjectVersionWithBody struct {
*object.ObjectVersionInfo `json:"info,omitempty"`
type EntityVersionWithBody struct {
*entity.EntityVersionInfo `json:"info,omitempty"`
Body []byte `json:"body,omitempty"`
}
type RawObjectWithHistory struct {
Object *object.RawObject `json:"object,omitempty"`
History []*ObjectVersionWithBody `json:"history,omitempty"`
type EntityWithHistory struct {
Entity *entity.Entity `json:"entity,omitempty"`
History []*EntityVersionWithBody `json:"history,omitempty"`
}
var (
// increment when RawObject changes
rawObjectVersion = 9
// increment when Entity changes
rawEntityVersion = 10
)
// Make sure we implement both store + admin
var _ object.ObjectStoreServer = &dummyObjectServer{}
var _ object.ObjectStoreAdminServer = &dummyObjectServer{}
var _ entity.EntityStoreServer = &dummyEntityServer{}
var _ entity.EntityStoreAdminServer = &dummyEntityServer{}
func ProvideDummyObjectServer(cfg *setting.Cfg, grpcServerProvider grpcserver.Provider, kinds kind.KindRegistry) object.ObjectStoreServer {
objectServer := &dummyObjectServer{
collection: persistentcollection.NewLocalFSPersistentCollection[*RawObjectWithHistory]("raw-object", cfg.DataPath, rawObjectVersion),
func ProvideDummyEntityServer(cfg *setting.Cfg, grpcServerProvider grpcserver.Provider, kinds kind.KindRegistry) entity.EntityStoreServer {
objectServer := &dummyEntityServer{
collection: persistentcollection.NewLocalFSPersistentCollection[*EntityWithHistory]("raw-object", cfg.DataPath, rawEntityVersion),
log: log.New("in-memory-object-server"),
kinds: kinds,
}
object.RegisterObjectStoreServer(grpcServerProvider.GetServer(), objectServer)
entity.RegisterEntityStoreServer(grpcServerProvider.GetServer(), objectServer)
return objectServer
}
type dummyObjectServer struct {
type dummyEntityServer struct {
log log.Logger
collection persistentcollection.PersistentCollection[*RawObjectWithHistory]
collection persistentcollection.PersistentCollection[*EntityWithHistory]
kinds kind.KindRegistry
}
func namespaceFromUID(grn *object.GRN) string {
func namespaceFromUID(grn *entity.GRN) string {
// TODO
return "orgId-1"
}
func (i *dummyObjectServer) findObject(ctx context.Context, grn *object.GRN, version string) (*RawObjectWithHistory, *object.RawObject, error) {
func (i *dummyEntityServer) findEntity(ctx context.Context, grn *entity.GRN, version string) (*EntityWithHistory, *entity.Entity, error) {
if grn == nil {
return nil, nil, errors.New("GRN must not be nil")
}
obj, err := i.collection.FindFirst(ctx, namespaceFromUID(grn), func(i *RawObjectWithHistory) (bool, error) {
return grn.Equals(i.Object.GRN), nil
obj, err := i.collection.FindFirst(ctx, namespaceFromUID(grn), func(i *EntityWithHistory) (bool, error) {
return grn.Equals(i.Entity.GRN), nil
})
if err != nil {
@ -79,21 +79,21 @@ func (i *dummyObjectServer) findObject(ctx context.Context, grn *object.GRN, ver
getLatestVersion := version == ""
if getLatestVersion {
return obj, obj.Object, nil
return obj, obj.Entity, nil
}
for _, objVersion := range obj.History {
if objVersion.Version == version {
copy := &object.RawObject{
GRN: obj.Object.GRN,
CreatedAt: obj.Object.CreatedAt,
CreatedBy: obj.Object.CreatedBy,
copy := &entity.Entity{
GRN: obj.Entity.GRN,
CreatedAt: obj.Entity.CreatedAt,
CreatedBy: obj.Entity.CreatedBy,
UpdatedAt: objVersion.UpdatedAt,
UpdatedBy: objVersion.UpdatedBy,
ETag: objVersion.ETag,
Version: objVersion.Version,
// Body is added from the dummy server cache (it does not exist in ObjectVersionInfo)
// Body is added from the dummy server cache (it does not exist in EntityVersionInfo)
Body: objVersion.Body,
}
@ -104,22 +104,22 @@ func (i *dummyObjectServer) findObject(ctx context.Context, grn *object.GRN, ver
return obj, nil, nil
}
func (i *dummyObjectServer) Read(ctx context.Context, r *object.ReadObjectRequest) (*object.ReadObjectResponse, error) {
func (i *dummyEntityServer) Read(ctx context.Context, r *entity.ReadEntityRequest) (*entity.ReadEntityResponse, error) {
grn := getFullGRN(ctx, r.GRN)
_, objVersion, err := i.findObject(ctx, grn, r.Version)
_, objVersion, err := i.findEntity(ctx, grn, r.Version)
if err != nil {
return nil, err
}
if objVersion == nil {
return &object.ReadObjectResponse{
Object: nil,
return &entity.ReadEntityResponse{
Entity: nil,
SummaryJson: nil,
}, nil
}
rsp := &object.ReadObjectResponse{
Object: objVersion,
rsp := &entity.ReadEntityResponse{
Entity: objVersion,
}
if r.WithSummary {
// Since we do not store the summary, we can just recreate on demand
@ -135,8 +135,8 @@ func (i *dummyObjectServer) Read(ctx context.Context, r *object.ReadObjectReques
return rsp, err
}
func (i *dummyObjectServer) BatchRead(ctx context.Context, batchR *object.BatchReadObjectRequest) (*object.BatchReadObjectResponse, error) {
results := make([]*object.ReadObjectResponse, 0)
func (i *dummyEntityServer) BatchRead(ctx context.Context, batchR *entity.BatchReadEntityRequest) (*entity.BatchReadEntityResponse, error) {
results := make([]*entity.ReadEntityResponse, 0)
for _, r := range batchR.Batch {
resp, err := i.Read(ctx, r)
if err != nil {
@ -145,7 +145,7 @@ func (i *dummyObjectServer) BatchRead(ctx context.Context, batchR *object.BatchR
results = append(results, resp)
}
return &object.BatchReadObjectResponse{Results: results}, nil
return &entity.BatchReadEntityResponse{Results: results}, nil
}
func createContentsHash(contents []byte) string {
@ -153,33 +153,33 @@ func createContentsHash(contents []byte) string {
return hex.EncodeToString(hash[:])
}
func (i *dummyObjectServer) update(ctx context.Context, r *object.AdminWriteObjectRequest, namespace string) (*object.WriteObjectResponse, error) {
func (i *dummyEntityServer) update(ctx context.Context, r *entity.AdminWriteEntityRequest, namespace string) (*entity.WriteEntityResponse, error) {
builder := i.kinds.GetSummaryBuilder(r.GRN.Kind)
if builder == nil {
return nil, fmt.Errorf("unsupported kind: " + r.GRN.Kind)
}
rsp := &object.WriteObjectResponse{}
rsp := &entity.WriteEntityResponse{}
updatedCount, err := i.collection.Update(ctx, namespace, func(i *RawObjectWithHistory) (bool, *RawObjectWithHistory, error) {
if !r.GRN.Equals(i.Object.GRN) {
updatedCount, err := i.collection.Update(ctx, namespace, func(i *EntityWithHistory) (bool, *EntityWithHistory, error) {
if !r.GRN.Equals(i.Entity.GRN) {
return false, nil, nil
}
if r.PreviousVersion != "" && i.Object.Version != r.PreviousVersion {
return false, nil, fmt.Errorf("expected the previous version to be %s, but was %s", r.PreviousVersion, i.Object.Version)
if r.PreviousVersion != "" && i.Entity.Version != r.PreviousVersion {
return false, nil, fmt.Errorf("expected the previous version to be %s, but was %s", r.PreviousVersion, i.Entity.Version)
}
prevVersion, err := strconv.Atoi(i.Object.Version)
prevVersion, err := strconv.Atoi(i.Entity.Version)
if err != nil {
return false, nil, err
}
modifier := store.UserFromContext(ctx)
updated := &object.RawObject{
updated := &entity.Entity{
GRN: r.GRN,
CreatedAt: i.Object.CreatedAt,
CreatedBy: i.Object.CreatedBy,
CreatedAt: i.Entity.CreatedAt,
CreatedBy: i.Entity.CreatedBy,
UpdatedAt: time.Now().UnixMilli(),
UpdatedBy: store.GetUserIDString(modifier),
Size: int64(len(r.Body)),
@ -188,9 +188,9 @@ func (i *dummyObjectServer) update(ctx context.Context, r *object.AdminWriteObje
Version: fmt.Sprintf("%d", prevVersion+1),
}
versionInfo := &ObjectVersionWithBody{
versionInfo := &EntityVersionWithBody{
Body: r.Body,
ObjectVersionInfo: &object.ObjectVersionInfo{
EntityVersionInfo: &entity.EntityVersionInfo{
Version: updated.Version,
UpdatedAt: updated.UpdatedAt,
UpdatedBy: updated.UpdatedBy,
@ -199,18 +199,18 @@ func (i *dummyObjectServer) update(ctx context.Context, r *object.AdminWriteObje
Comment: r.Comment,
},
}
rsp.Object = versionInfo.ObjectVersionInfo
rsp.Status = object.WriteObjectResponse_UPDATED
rsp.Entity = versionInfo.EntityVersionInfo
rsp.Status = entity.WriteEntityResponse_UPDATED
// When saving, it must be different than the head version
if i.Object.ETag == updated.ETag {
versionInfo.ObjectVersionInfo.Version = i.Object.Version
rsp.Status = object.WriteObjectResponse_UNCHANGED
if i.Entity.ETag == updated.ETag {
versionInfo.EntityVersionInfo.Version = i.Entity.Version
rsp.Status = entity.WriteEntityResponse_UNCHANGED
return false, nil, nil
}
return true, &RawObjectWithHistory{
Object: updated,
return true, &EntityWithHistory{
Entity: updated,
History: append(i.History, versionInfo),
}, nil
})
@ -219,16 +219,16 @@ func (i *dummyObjectServer) update(ctx context.Context, r *object.AdminWriteObje
return nil, err
}
if updatedCount == 0 && rsp.Object == nil {
if updatedCount == 0 && rsp.Entity == nil {
return nil, fmt.Errorf("could not find object: %v", r.GRN)
}
return rsp, nil
}
func (i *dummyObjectServer) insert(ctx context.Context, r *object.AdminWriteObjectRequest, namespace string) (*object.WriteObjectResponse, error) {
func (i *dummyEntityServer) insert(ctx context.Context, r *entity.AdminWriteEntityRequest, namespace string) (*entity.WriteEntityResponse, error) {
modifier := store.GetUserIDString(store.UserFromContext(ctx))
rawObj := &object.RawObject{
rawObj := &entity.Entity{
GRN: r.GRN,
UpdatedAt: time.Now().UnixMilli(),
CreatedAt: time.Now().UnixMilli(),
@ -240,7 +240,7 @@ func (i *dummyObjectServer) insert(ctx context.Context, r *object.AdminWriteObje
Version: fmt.Sprintf("%d", 1),
}
info := &object.ObjectVersionInfo{
info := &entity.EntityVersionInfo{
Version: rawObj.Version,
UpdatedAt: rawObj.UpdatedAt,
UpdatedBy: rawObj.UpdatedBy,
@ -249,10 +249,10 @@ func (i *dummyObjectServer) insert(ctx context.Context, r *object.AdminWriteObje
Comment: r.Comment,
}
newObj := &RawObjectWithHistory{
Object: rawObj,
History: []*ObjectVersionWithBody{{
ObjectVersionInfo: info,
newObj := &EntityWithHistory{
Entity: rawObj,
History: []*EntityVersionWithBody{{
EntityVersionInfo: info,
Body: r.Body,
}},
}
@ -262,30 +262,30 @@ func (i *dummyObjectServer) insert(ctx context.Context, r *object.AdminWriteObje
return nil, err
}
return &object.WriteObjectResponse{
return &entity.WriteEntityResponse{
Error: nil,
Object: info,
Status: object.WriteObjectResponse_CREATED,
Entity: info,
Status: entity.WriteEntityResponse_CREATED,
}, nil
}
func (i *dummyObjectServer) Write(ctx context.Context, r *object.WriteObjectRequest) (*object.WriteObjectResponse, error) {
return i.doWrite(ctx, object.ToAdminWriteObjectRequest(r))
func (i *dummyEntityServer) Write(ctx context.Context, r *entity.WriteEntityRequest) (*entity.WriteEntityResponse, error) {
return i.doWrite(ctx, entity.ToAdminWriteEntityRequest(r))
}
func (i *dummyObjectServer) AdminWrite(ctx context.Context, r *object.AdminWriteObjectRequest) (*object.WriteObjectResponse, error) {
func (i *dummyEntityServer) AdminWrite(ctx context.Context, r *entity.AdminWriteEntityRequest) (*entity.WriteEntityResponse, error) {
// Check permissions?
return i.doWrite(ctx, r)
}
func (i *dummyObjectServer) doWrite(ctx context.Context, r *object.AdminWriteObjectRequest) (*object.WriteObjectResponse, error) {
func (i *dummyEntityServer) doWrite(ctx context.Context, r *entity.AdminWriteEntityRequest) (*entity.WriteEntityResponse, error) {
grn := getFullGRN(ctx, r.GRN)
namespace := namespaceFromUID(grn)
obj, err := i.collection.FindFirst(ctx, namespace, func(i *RawObjectWithHistory) (bool, error) {
obj, err := i.collection.FindFirst(ctx, namespace, func(i *EntityWithHistory) (bool, error) {
if i == nil || r == nil {
return false, nil
}
return grn.Equals(i.Object.GRN), nil
return grn.Equals(i.Entity.GRN), nil
})
if err != nil {
return nil, err
@ -298,12 +298,12 @@ func (i *dummyObjectServer) doWrite(ctx context.Context, r *object.AdminWriteObj
return i.update(ctx, r, namespace)
}
func (i *dummyObjectServer) Delete(ctx context.Context, r *object.DeleteObjectRequest) (*object.DeleteObjectResponse, error) {
func (i *dummyEntityServer) Delete(ctx context.Context, r *entity.DeleteEntityRequest) (*entity.DeleteEntityResponse, error) {
grn := getFullGRN(ctx, r.GRN)
_, err := i.collection.Delete(ctx, namespaceFromUID(grn), func(i *RawObjectWithHistory) (bool, error) {
if grn.Equals(i.Object.GRN) {
if r.PreviousVersion != "" && i.Object.Version != r.PreviousVersion {
return false, fmt.Errorf("expected the previous version to be %s, but was %s", r.PreviousVersion, i.Object.Version)
_, err := i.collection.Delete(ctx, namespaceFromUID(grn), func(i *EntityWithHistory) (bool, error) {
if grn.Equals(i.Entity.GRN) {
if r.PreviousVersion != "" && i.Entity.Version != r.PreviousVersion {
return false, fmt.Errorf("expected the previous version to be %s, but was %s", r.PreviousVersion, i.Entity.Version)
}
return true, nil
@ -316,30 +316,30 @@ func (i *dummyObjectServer) Delete(ctx context.Context, r *object.DeleteObjectRe
return nil, err
}
return &object.DeleteObjectResponse{
return &entity.DeleteEntityResponse{
OK: true,
}, nil
}
func (i *dummyObjectServer) History(ctx context.Context, r *object.ObjectHistoryRequest) (*object.ObjectHistoryResponse, error) {
func (i *dummyEntityServer) History(ctx context.Context, r *entity.EntityHistoryRequest) (*entity.EntityHistoryResponse, error) {
grn := getFullGRN(ctx, r.GRN)
obj, _, err := i.findObject(ctx, grn, "")
obj, _, err := i.findEntity(ctx, grn, "")
if err != nil {
return nil, err
}
rsp := &object.ObjectHistoryResponse{}
rsp := &entity.EntityHistoryResponse{}
if obj != nil {
// Return the most recent versions first
// Better? save them in this order?
for i := len(obj.History) - 1; i >= 0; i-- {
rsp.Versions = append(rsp.Versions, obj.History[i].ObjectVersionInfo)
rsp.Versions = append(rsp.Versions, obj.History[i].EntityVersionInfo)
}
}
return rsp, nil
}
func (i *dummyObjectServer) Search(ctx context.Context, r *object.ObjectSearchRequest) (*object.ObjectSearchResponse, error) {
func (i *dummyEntityServer) Search(ctx context.Context, r *entity.EntitySearchRequest) (*entity.EntitySearchResponse, error) {
var kindMap map[string]bool
if len(r.Kind) != 0 {
kindMap = make(map[string]bool)
@ -349,9 +349,9 @@ func (i *dummyObjectServer) Search(ctx context.Context, r *object.ObjectSearchRe
}
// TODO more filters
objects, err := i.collection.Find(ctx, namespaceFromUID(&object.GRN{}), func(i *RawObjectWithHistory) (bool, error) {
objects, err := i.collection.Find(ctx, namespaceFromUID(&entity.GRN{}), func(i *EntityWithHistory) (bool, error) {
if len(r.Kind) != 0 {
if _, ok := kindMap[i.Object.GRN.Kind]; !ok {
if _, ok := kindMap[i.Entity.GRN.Kind]; !ok {
return false, nil
}
}
@ -361,35 +361,35 @@ func (i *dummyObjectServer) Search(ctx context.Context, r *object.ObjectSearchRe
return nil, err
}
searchResults := make([]*object.ObjectSearchResult, 0)
searchResults := make([]*entity.EntitySearchResult, 0)
for _, o := range objects {
builder := i.kinds.GetSummaryBuilder(o.Object.GRN.Kind)
builder := i.kinds.GetSummaryBuilder(o.Entity.GRN.Kind)
if builder == nil {
continue
}
summary, clean, e2 := builder(ctx, o.Object.GRN.UID, o.Object.Body)
summary, clean, e2 := builder(ctx, o.Entity.GRN.UID, o.Entity.Body)
if e2 != nil {
continue
}
searchResults = append(searchResults, &object.ObjectSearchResult{
GRN: o.Object.GRN,
Version: o.Object.Version,
UpdatedAt: o.Object.UpdatedAt,
UpdatedBy: o.Object.UpdatedBy,
searchResults = append(searchResults, &entity.EntitySearchResult{
GRN: o.Entity.GRN,
Version: o.Entity.Version,
UpdatedAt: o.Entity.UpdatedAt,
UpdatedBy: o.Entity.UpdatedBy,
Name: summary.Name,
Description: summary.Description,
Body: clean,
})
}
return &object.ObjectSearchResponse{
return &entity.EntitySearchResponse{
Results: searchResults,
}, nil
}
// This sets the TenantId on the request GRN
func getFullGRN(ctx context.Context, grn *object.GRN) *object.GRN {
func getFullGRN(ctx context.Context, grn *entity.GRN) *entity.GRN {
if grn.TenantId == 0 {
modifier := store.UserFromContext(ctx)
grn.TenantId = modifier.OrgID

View File

@ -1,11 +1,11 @@
package objectdummyserver
package dummy
import (
"encoding/json"
"fmt"
"testing"
"github.com/grafana/grafana/pkg/services/store/object"
"github.com/grafana/grafana/pkg/services/store/entity"
"github.com/stretchr/testify/require"
)
@ -16,8 +16,8 @@ func TestRawEncoders(t *testing.T) {
})
require.NoError(t, err)
raw := &ObjectVersionWithBody{
&object.ObjectVersionInfo{
raw := &EntityVersionWithBody{
&entity.EntityVersionInfo{
Version: "A",
},
body,
@ -30,28 +30,28 @@ func TestRawEncoders(t *testing.T) {
fmt.Printf("expect: %s", str)
require.JSONEq(t, `{"info":{"version":"A"},"body":"eyJmaWVsZCI6MS4yMywiaGVsbG8iOiJ3b3JsZCJ9"}`, str)
copy := &ObjectVersionWithBody{}
copy := &EntityVersionWithBody{}
err = json.Unmarshal(b, copy)
require.NoError(t, err)
}
func TestRawObjectWithHistory(t *testing.T) {
func TestRawEntityWithHistory(t *testing.T) {
body, err := json.Marshal(map[string]interface{}{
"hello": "world",
"field": 1.23,
})
require.NoError(t, err)
raw := &RawObjectWithHistory{
Object: &object.RawObject{
GRN: &object.GRN{UID: "x"},
raw := &EntityWithHistory{
Entity: &entity.Entity{
GRN: &entity.GRN{UID: "x"},
Version: "A",
Body: body,
},
History: make([]*ObjectVersionWithBody, 0),
History: make([]*EntityVersionWithBody, 0),
}
raw.History = append(raw.History, &ObjectVersionWithBody{
&object.ObjectVersionInfo{
raw.History = append(raw.History, &EntityVersionWithBody{
&entity.EntityVersionInfo{
Version: "B",
},
body,
@ -63,7 +63,7 @@ func TestRawObjectWithHistory(t *testing.T) {
str := string(b)
//fmt.Printf("expect: %s", str)
require.JSONEq(t, `{
"object": {
"entity": {
"GRN": {
"UID": "x"
},
@ -83,7 +83,7 @@ func TestRawObjectWithHistory(t *testing.T) {
]
}`, str)
copy := &ObjectVersionWithBody{}
copy := &EntityVersionWithBody{}
err = json.Unmarshal(b, copy)
require.NoError(t, err)
}

View File

@ -0,0 +1,46 @@
package dummy
import (
"context"
"fmt"
"github.com/grafana/grafana/pkg/services/store/entity"
)
// Make sure we implement both store + admin
var _ entity.EntityStoreServer = &fakeEntityStore{}
var _ entity.EntityStoreAdminServer = &fakeEntityStore{}
func ProvideFakeEntityServer() entity.EntityStoreServer {
return &fakeEntityStore{}
}
type fakeEntityStore struct{}
func (i fakeEntityStore) AdminWrite(ctx context.Context, r *entity.AdminWriteEntityRequest) (*entity.WriteEntityResponse, error) {
return nil, fmt.Errorf("unimplemented")
}
func (i fakeEntityStore) Write(ctx context.Context, r *entity.WriteEntityRequest) (*entity.WriteEntityResponse, error) {
return nil, fmt.Errorf("unimplemented")
}
func (i fakeEntityStore) Read(ctx context.Context, r *entity.ReadEntityRequest) (*entity.ReadEntityResponse, error) {
return nil, fmt.Errorf("unimplemented")
}
func (i fakeEntityStore) BatchRead(ctx context.Context, batchR *entity.BatchReadEntityRequest) (*entity.BatchReadEntityResponse, error) {
return nil, fmt.Errorf("unimplemented")
}
func (i fakeEntityStore) Delete(ctx context.Context, r *entity.DeleteEntityRequest) (*entity.DeleteEntityResponse, error) {
return nil, fmt.Errorf("unimplemented")
}
func (i fakeEntityStore) History(ctx context.Context, r *entity.EntityHistoryRequest) (*entity.EntityHistoryResponse, error) {
return nil, fmt.Errorf("unimplemented")
}
func (i fakeEntityStore) Search(ctx context.Context, r *entity.EntitySearchRequest) (*entity.EntitySearchResponse, error) {
return nil, fmt.Errorf("unimplemented")
}

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
syntax = "proto3";
package object;
package entity;
option go_package = "./;object";
option go_package = "./;entity";
message GRN {
// the tenant/org id
int64 tenant_id = 1;
// Identify the object kind. This kind will be used to apply a schema to the body and
// Identify the entity kind. This kind will be used to apply a schema to the body and
// will trigger additional indexing behavior.
string kind = 3;
@ -16,21 +16,21 @@ message GRN {
string UID = 4;
}
// The canonical object/document data -- this represents the raw bytes and storage level metadata
message RawObject {
// Object identifier
// The canonical entity/document data -- this represents the raw bytes and storage level metadata
message Entity {
// Entity identifier
GRN GRN = 1;
// Time in epoch milliseconds that the object was created
// Time in epoch milliseconds that the entity was created
int64 created_at = 2;
// Time in epoch milliseconds that the object was updated
// Time in epoch milliseconds that the entity was updated
int64 updated_at = 3;
// Who created the object
// Who created the entity
string created_by = 4;
// Who updated the object
// Who updated the entity
string updated_by = 5;
// Content Length
@ -39,7 +39,7 @@ message RawObject {
// MD5 digest of the body
string ETag = 7;
// Raw bytes of the storage object. The kind will determine what is a valid payload
// Raw bytes of the storage entity. The kind will determine what is a valid payload
bytes body = 8;
// Folder UID
@ -48,29 +48,29 @@ message RawObject {
// Unique slug within folder (may be UID)
string slug = 10;
// The version will change when the object is saved. It is not necessarily sortable
// The version will change when the entity is saved. It is not necessarily sortable
//
// NOTE: currently managed by the dashboard+dashboard_version tables
string version = 11;
// External location info
ObjectOriginInfo origin = 12;
EntityOriginInfo origin = 12;
}
message ObjectOriginInfo {
message EntityOriginInfo {
// NOTE: currently managed by the dashboard_provisioning table
string source = 1;
// Key in the upstream system
string key = 2;
// Time in epoch milliseconds that the object was last synced with an external system (provisioning/git)
// Time in epoch milliseconds that the entity was last synced with an external system (provisioning/git)
int64 time = 3;
}
// Report error while working with objects
// Report error while working with entitys
// NOTE: real systems at scale will contain errors.
message ObjectErrorInfo {
message EntityErrorInfo {
// Match an error code registry?
int64 code = 1;
@ -81,15 +81,15 @@ message ObjectErrorInfo {
bytes details_json = 3;
}
// This is a subset of RawObject that does not include body or sync info
message ObjectVersionInfo {
// The version will change when the object is saved. It is not necessarily sortable
// This is a subset of Entity that does not include body or sync info
message EntityVersionInfo {
// The version will change when the entity is saved. It is not necessarily sortable
string version = 1;
// Time in epoch milliseconds that the object was updated
// Time in epoch milliseconds that the entity was updated
int64 updated_at = 2;
// Who updated the object
// Who updated the entity
string updated_by = 3;
// Content Length
@ -108,8 +108,8 @@ message ObjectVersionInfo {
// Get request/response
//-----------------------------------------------
message ReadObjectRequest {
// Object identifier
message ReadEntityRequest {
// Entity identifier
GRN GRN = 1;
// Fetch an explicit version
@ -122,11 +122,11 @@ message ReadObjectRequest {
bool with_summary = 4;
}
message ReadObjectResponse {
// Object details with the body removed
RawObject object = 1;
message ReadEntityResponse {
// Entity details with the body removed
Entity entity = 1;
// Object summary as JSON
// Entity summary as JSON
bytes summary_json = 2;
}
@ -134,29 +134,29 @@ message ReadObjectResponse {
// Make many read requests at once (by Kind+ID+version)
//------------------------------------------------------
message BatchReadObjectRequest {
repeated ReadObjectRequest batch = 1;
message BatchReadEntityRequest {
repeated ReadEntityRequest batch = 1;
}
message BatchReadObjectResponse {
repeated ReadObjectResponse results = 1;
message BatchReadEntityResponse {
repeated ReadEntityResponse results = 1;
}
//-----------------------------------------------
// Write request/response
//-----------------------------------------------
message WriteObjectRequest {
// Object identifier
message WriteEntityRequest {
// Entity identifier
GRN GRN = 1;
// Where to save the object (empty will leave it unchanged)
// Where to save the entity (empty will leave it unchanged)
string folder = 2;
// The raw object body
// The raw entity body
bytes body = 3;
// Message that can be seen when exploring object history
// Message that can be seen when exploring entity history
string comment = 4;
// Used for optimistic locking. If missing, the previous version will be replaced regardless
@ -166,32 +166,32 @@ message WriteObjectRequest {
// This operation is useful when syncing a resource from external sources
// that have more accurate metadata information (git, or an archive).
// This process can bypass the forced checks that
message AdminWriteObjectRequest {
// Object identifier
message AdminWriteEntityRequest {
// Entity identifier
GRN GRN = 1;
// Where to save the object (empty will leave it unchanged)
// Where to save the entity (empty will leave it unchanged)
string folder = 2;
// The raw object body
// The raw entity body
bytes body = 3;
// Message that can be seen when exploring object history
// Message that can be seen when exploring entity history
string comment = 4;
// Time in epoch milliseconds that the object was created
// Time in epoch milliseconds that the entity was created
// Optional, if 0 it will use the current time
int64 created_at = 5;
// Time in epoch milliseconds that the object was updated
// Time in epoch milliseconds that the entity was updated
// Optional, if empty it will use the current user
int64 updated_at = 6;
// Who created the object
// Who created the entity
// Optional, if 0 it will use the current time
string created_by = 7;
// Who updated the object
// Who updated the entity
// Optional, if empty it will use the current user
string updated_by = 8;
@ -207,21 +207,21 @@ message AdminWriteObjectRequest {
// This will make sense for systems that manage history explicitly externallay
bool clear_history = 11;
// Optionally define where the object came from
ObjectOriginInfo origin = 12;
// Optionally define where the entity came from
EntityOriginInfo origin = 12;
}
message WriteObjectResponse {
message WriteEntityResponse {
// Error info -- if exists, the save did not happen
ObjectErrorInfo error = 1;
EntityErrorInfo error = 1;
// Object identifier
// Entity identifier
GRN GRN = 2;
// Object details with the body removed
ObjectVersionInfo object = 3;
// Entity details with the body removed
EntityVersionInfo entity = 3;
// Object summary as JSON
// Entity summary as JSON
bytes summary_json = 4;
// Status code
@ -240,15 +240,15 @@ message WriteObjectResponse {
// Delete request/response
//-----------------------------------------------
message DeleteObjectRequest {
// Object identifier
message DeleteEntityRequest {
// Entity identifier
GRN GRN = 1;
// Used for optimistic locking. If missing, the previous version will be replaced regardless
string previous_version = 3;
}
message DeleteObjectResponse {
message DeleteEntityResponse {
bool OK = 1;
}
@ -256,8 +256,8 @@ message DeleteObjectResponse {
// History request/response
//-----------------------------------------------
message ObjectHistoryRequest {
// Object identifier
message EntityHistoryRequest {
// Entity identifier
GRN GRN = 1;
// Maximum number of items to return
@ -267,12 +267,12 @@ message ObjectHistoryRequest {
string next_page_token = 5;
}
message ObjectHistoryResponse {
// Object identifier
message EntityHistoryResponse {
// Entity identifier
GRN GRN = 1;
// Object metadata without the raw bytes
repeated ObjectVersionInfo versions = 2;
// Entity metadata without the raw bytes
repeated EntityVersionInfo versions = 2;
// More results exist... pass this in the next request
string next_page_token = 3;
@ -283,7 +283,7 @@ message ObjectHistoryResponse {
// List request/response
//-----------------------------------------------
message ObjectSearchRequest {
message EntitySearchRequest {
// Starting from the requested page (other query parameters must match!)
string next_page_token = 1;
@ -315,24 +315,24 @@ message ObjectSearchRequest {
bool with_fields = 10;
}
// Search result metadata for each object
message ObjectSearchResult {
// Object identifier
// Search result metadata for each entity
message EntitySearchResult {
// Entity identifier
GRN GRN = 1;
// The current veresion of this object
// The current veresion of this entity
string version = 2;
// Content Length
int64 size = 3;
// Time in epoch milliseconds that the object was updated
// Time in epoch milliseconds that the entity was updated
int64 updated_at = 4;
// Who updated the object
// Who updated the entity
string updated_by = 5;
// Optionally include the full object body
// Optionally include the full entity body
bytes body = 6;
//----------------------------------------
@ -357,12 +357,12 @@ message ObjectSearchResult {
// Optionally include extracted JSON
bytes fields_json = 12;
// ObjectErrorInfo in json
// EntityErrorInfo in json
bytes error_json = 13;
}
message ObjectSearchResponse {
repeated ObjectSearchResult results = 1;
message EntitySearchResponse {
repeated EntitySearchResult results = 1;
// More results exist... pass this in the next request
string next_page_token = 2;
@ -373,25 +373,25 @@ message ObjectSearchResponse {
// Storage interface
//-----------------------------------------------
// The object store provides a basic CRUD (+watch eventually) interface for generic objects
service ObjectStore {
rpc Read(ReadObjectRequest) returns (ReadObjectResponse);
rpc BatchRead(BatchReadObjectRequest) returns (BatchReadObjectResponse);
rpc Write(WriteObjectRequest) returns (WriteObjectResponse);
rpc Delete(DeleteObjectRequest) returns (DeleteObjectResponse);
rpc History(ObjectHistoryRequest) returns (ObjectHistoryResponse);
rpc Search(ObjectSearchRequest) returns (ObjectSearchResponse);
// The entity store provides a basic CRUD (+watch eventually) interface for generic entitys
service EntityStore {
rpc Read(ReadEntityRequest) returns (ReadEntityResponse);
rpc BatchRead(BatchReadEntityRequest) returns (BatchReadEntityResponse);
rpc Write(WriteEntityRequest) returns (WriteEntityResponse);
rpc Delete(DeleteEntityRequest) returns (DeleteEntityResponse);
rpc History(EntityHistoryRequest) returns (EntityHistoryResponse);
rpc Search(EntitySearchRequest) returns (EntitySearchResponse);
// Ideally an additional search endpoint with more flexibility to limit what you actually care about
// https://github.com/grafana/grafana-plugin-sdk-go/blob/main/proto/backend.proto#L129
// rpc SearchEX(ObjectSearchRequest) returns (DataResponse);
// rpc SearchEX(EntitySearchRequest) returns (DataResponse);
// TEMPORARY... while we split this into a new service (see below)
rpc AdminWrite(AdminWriteObjectRequest) returns (WriteObjectResponse);
rpc AdminWrite(AdminWriteEntityRequest) returns (WriteEntityResponse);
}
// The admin service extends the basic object store interface, but provides
// The admin service extends the basic entity store interface, but provides
// more explicit control that can support bulk operations like efficient git sync
service ObjectStoreAdmin {
rpc AdminWrite(AdminWriteObjectRequest) returns (WriteObjectResponse);
service EntityStoreAdmin {
rpc AdminWrite(AdminWriteEntityRequest) returns (WriteEntityResponse);
}

View File

@ -0,0 +1,405 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.21.9
// source: entity.proto
package entity
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// 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
// 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.
type EntityStoreClient interface {
Read(ctx context.Context, in *ReadEntityRequest, opts ...grpc.CallOption) (*ReadEntityResponse, error)
BatchRead(ctx context.Context, in *BatchReadEntityRequest, opts ...grpc.CallOption) (*BatchReadEntityResponse, error)
Write(ctx context.Context, in *WriteEntityRequest, opts ...grpc.CallOption) (*WriteEntityResponse, error)
Delete(ctx context.Context, in *DeleteEntityRequest, opts ...grpc.CallOption) (*DeleteEntityResponse, error)
History(ctx context.Context, in *EntityHistoryRequest, opts ...grpc.CallOption) (*EntityHistoryResponse, error)
Search(ctx context.Context, in *EntitySearchRequest, opts ...grpc.CallOption) (*EntitySearchResponse, error)
// TEMPORARY... while we split this into a new service (see below)
AdminWrite(ctx context.Context, in *AdminWriteEntityRequest, opts ...grpc.CallOption) (*WriteEntityResponse, error)
}
type entityStoreClient struct {
cc grpc.ClientConnInterface
}
func NewEntityStoreClient(cc grpc.ClientConnInterface) EntityStoreClient {
return &entityStoreClient{cc}
}
func (c *entityStoreClient) Read(ctx context.Context, in *ReadEntityRequest, opts ...grpc.CallOption) (*ReadEntityResponse, error) {
out := new(ReadEntityResponse)
err := c.cc.Invoke(ctx, "/entity.EntityStore/Read", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *entityStoreClient) BatchRead(ctx context.Context, in *BatchReadEntityRequest, opts ...grpc.CallOption) (*BatchReadEntityResponse, error) {
out := new(BatchReadEntityResponse)
err := c.cc.Invoke(ctx, "/entity.EntityStore/BatchRead", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *entityStoreClient) Write(ctx context.Context, in *WriteEntityRequest, opts ...grpc.CallOption) (*WriteEntityResponse, error) {
out := new(WriteEntityResponse)
err := c.cc.Invoke(ctx, "/entity.EntityStore/Write", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *entityStoreClient) Delete(ctx context.Context, in *DeleteEntityRequest, opts ...grpc.CallOption) (*DeleteEntityResponse, error) {
out := new(DeleteEntityResponse)
err := c.cc.Invoke(ctx, "/entity.EntityStore/Delete", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *entityStoreClient) History(ctx context.Context, in *EntityHistoryRequest, opts ...grpc.CallOption) (*EntityHistoryResponse, error) {
out := new(EntityHistoryResponse)
err := c.cc.Invoke(ctx, "/entity.EntityStore/History", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *entityStoreClient) Search(ctx context.Context, in *EntitySearchRequest, opts ...grpc.CallOption) (*EntitySearchResponse, error) {
out := new(EntitySearchResponse)
err := c.cc.Invoke(ctx, "/entity.EntityStore/Search", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *entityStoreClient) AdminWrite(ctx context.Context, in *AdminWriteEntityRequest, opts ...grpc.CallOption) (*WriteEntityResponse, error) {
out := new(WriteEntityResponse)
err := c.cc.Invoke(ctx, "/entity.EntityStore/AdminWrite", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// EntityStoreServer is the server API for EntityStore service.
// All implementations should embed UnimplementedEntityStoreServer
// for forward compatibility
type EntityStoreServer interface {
Read(context.Context, *ReadEntityRequest) (*ReadEntityResponse, error)
BatchRead(context.Context, *BatchReadEntityRequest) (*BatchReadEntityResponse, error)
Write(context.Context, *WriteEntityRequest) (*WriteEntityResponse, error)
Delete(context.Context, *DeleteEntityRequest) (*DeleteEntityResponse, error)
History(context.Context, *EntityHistoryRequest) (*EntityHistoryResponse, error)
Search(context.Context, *EntitySearchRequest) (*EntitySearchResponse, error)
// TEMPORARY... while we split this into a new service (see below)
AdminWrite(context.Context, *AdminWriteEntityRequest) (*WriteEntityResponse, error)
}
// UnimplementedEntityStoreServer should be embedded to have forward compatible implementations.
type UnimplementedEntityStoreServer struct {
}
func (UnimplementedEntityStoreServer) Read(context.Context, *ReadEntityRequest) (*ReadEntityResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Read not implemented")
}
func (UnimplementedEntityStoreServer) BatchRead(context.Context, *BatchReadEntityRequest) (*BatchReadEntityResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method BatchRead not implemented")
}
func (UnimplementedEntityStoreServer) Write(context.Context, *WriteEntityRequest) (*WriteEntityResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Write not implemented")
}
func (UnimplementedEntityStoreServer) Delete(context.Context, *DeleteEntityRequest) (*DeleteEntityResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented")
}
func (UnimplementedEntityStoreServer) History(context.Context, *EntityHistoryRequest) (*EntityHistoryResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method History not implemented")
}
func (UnimplementedEntityStoreServer) Search(context.Context, *EntitySearchRequest) (*EntitySearchResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Search not implemented")
}
func (UnimplementedEntityStoreServer) AdminWrite(context.Context, *AdminWriteEntityRequest) (*WriteEntityResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AdminWrite not implemented")
}
// UnsafeEntityStoreServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to EntityStoreServer will
// result in compilation errors.
type UnsafeEntityStoreServer interface {
mustEmbedUnimplementedEntityStoreServer()
}
func RegisterEntityStoreServer(s grpc.ServiceRegistrar, srv EntityStoreServer) {
s.RegisterService(&EntityStore_ServiceDesc, srv)
}
func _EntityStore_Read_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ReadEntityRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(EntityStoreServer).Read(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/entity.EntityStore/Read",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(EntityStoreServer).Read(ctx, req.(*ReadEntityRequest))
}
return interceptor(ctx, in, info, handler)
}
func _EntityStore_BatchRead_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(BatchReadEntityRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(EntityStoreServer).BatchRead(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/entity.EntityStore/BatchRead",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(EntityStoreServer).BatchRead(ctx, req.(*BatchReadEntityRequest))
}
return interceptor(ctx, in, info, handler)
}
func _EntityStore_Write_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(WriteEntityRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(EntityStoreServer).Write(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/entity.EntityStore/Write",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(EntityStoreServer).Write(ctx, req.(*WriteEntityRequest))
}
return interceptor(ctx, in, info, handler)
}
func _EntityStore_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteEntityRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(EntityStoreServer).Delete(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/entity.EntityStore/Delete",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(EntityStoreServer).Delete(ctx, req.(*DeleteEntityRequest))
}
return interceptor(ctx, in, info, handler)
}
func _EntityStore_History_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(EntityHistoryRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(EntityStoreServer).History(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/entity.EntityStore/History",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(EntityStoreServer).History(ctx, req.(*EntityHistoryRequest))
}
return interceptor(ctx, in, info, handler)
}
func _EntityStore_Search_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(EntitySearchRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(EntityStoreServer).Search(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/entity.EntityStore/Search",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(EntityStoreServer).Search(ctx, req.(*EntitySearchRequest))
}
return interceptor(ctx, in, info, handler)
}
func _EntityStore_AdminWrite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AdminWriteEntityRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(EntityStoreServer).AdminWrite(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/entity.EntityStore/AdminWrite",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(EntityStoreServer).AdminWrite(ctx, req.(*AdminWriteEntityRequest))
}
return interceptor(ctx, in, info, handler)
}
// EntityStore_ServiceDesc is the grpc.ServiceDesc for EntityStore service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var EntityStore_ServiceDesc = grpc.ServiceDesc{
ServiceName: "entity.EntityStore",
HandlerType: (*EntityStoreServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Read",
Handler: _EntityStore_Read_Handler,
},
{
MethodName: "BatchRead",
Handler: _EntityStore_BatchRead_Handler,
},
{
MethodName: "Write",
Handler: _EntityStore_Write_Handler,
},
{
MethodName: "Delete",
Handler: _EntityStore_Delete_Handler,
},
{
MethodName: "History",
Handler: _EntityStore_History_Handler,
},
{
MethodName: "Search",
Handler: _EntityStore_Search_Handler,
},
{
MethodName: "AdminWrite",
Handler: _EntityStore_AdminWrite_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "entity.proto",
}
// EntityStoreAdminClient is the client API for EntityStoreAdmin 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.
type EntityStoreAdminClient interface {
AdminWrite(ctx context.Context, in *AdminWriteEntityRequest, opts ...grpc.CallOption) (*WriteEntityResponse, error)
}
type entityStoreAdminClient struct {
cc grpc.ClientConnInterface
}
func NewEntityStoreAdminClient(cc grpc.ClientConnInterface) EntityStoreAdminClient {
return &entityStoreAdminClient{cc}
}
func (c *entityStoreAdminClient) AdminWrite(ctx context.Context, in *AdminWriteEntityRequest, opts ...grpc.CallOption) (*WriteEntityResponse, error) {
out := new(WriteEntityResponse)
err := c.cc.Invoke(ctx, "/entity.EntityStoreAdmin/AdminWrite", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// EntityStoreAdminServer is the server API for EntityStoreAdmin service.
// All implementations should embed UnimplementedEntityStoreAdminServer
// for forward compatibility
type EntityStoreAdminServer interface {
AdminWrite(context.Context, *AdminWriteEntityRequest) (*WriteEntityResponse, error)
}
// UnimplementedEntityStoreAdminServer should be embedded to have forward compatible implementations.
type UnimplementedEntityStoreAdminServer struct {
}
func (UnimplementedEntityStoreAdminServer) AdminWrite(context.Context, *AdminWriteEntityRequest) (*WriteEntityResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AdminWrite not implemented")
}
// UnsafeEntityStoreAdminServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to EntityStoreAdminServer will
// result in compilation errors.
type UnsafeEntityStoreAdminServer interface {
mustEmbedUnimplementedEntityStoreAdminServer()
}
func RegisterEntityStoreAdminServer(s grpc.ServiceRegistrar, srv EntityStoreAdminServer) {
s.RegisterService(&EntityStoreAdmin_ServiceDesc, srv)
}
func _EntityStoreAdmin_AdminWrite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AdminWriteEntityRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(EntityStoreAdminServer).AdminWrite(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/entity.EntityStoreAdmin/AdminWrite",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(EntityStoreAdminServer).AdminWrite(ctx, req.(*AdminWriteEntityRequest))
}
return interceptor(ctx, in, info, handler)
}
// EntityStoreAdmin_ServiceDesc is the grpc.ServiceDesc for EntityStoreAdmin service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var EntityStoreAdmin_ServiceDesc = grpc.ServiceDesc{
ServiceName: "entity.EntityStoreAdmin",
HandlerType: (*EntityStoreAdminServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "AdminWrite",
Handler: _EntityStoreAdmin_AdminWrite_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "entity.proto",
}

View File

@ -17,5 +17,5 @@ cd "$DIR"
protoc -I ./ \
--go_out=${DST_DIR} \
--go-grpc_out=${DST_DIR} --go-grpc_opt=require_unimplemented_servers=false \
object.proto
entity.proto

View File

@ -1,4 +1,4 @@
package object
package entity
import (
"fmt"

View File

@ -1,4 +1,4 @@
package httpobjectstore
package httpentitystore
import (
"fmt"
@ -10,8 +10,8 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/services/store/entity"
"github.com/grafana/grafana/pkg/services/store/kind"
"github.com/grafana/grafana/pkg/services/store/object"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
@ -20,35 +20,35 @@ import (
"github.com/grafana/grafana/pkg/models"
)
type HTTPObjectStore interface {
type HTTPEntityStore interface {
// Register HTTP Access to the store
RegisterHTTPRoutes(routing.RouteRegister)
}
type httpObjectStore struct {
store object.ObjectStoreServer
type httpEntityStore struct {
store entity.EntityStoreServer
log log.Logger
kinds kind.KindRegistry
}
func ProvideHTTPObjectStore(store object.ObjectStoreServer, kinds kind.KindRegistry) HTTPObjectStore {
return &httpObjectStore{
func ProvideHTTPEntityStore(store entity.EntityStoreServer, kinds kind.KindRegistry) HTTPEntityStore {
return &httpEntityStore{
store: store,
log: log.New("http-object-store"),
log: log.New("http-entity-store"),
kinds: kinds,
}
}
// All registered under "api/object"
func (s *httpObjectStore) RegisterHTTPRoutes(route routing.RouteRegister) {
// All registered under "api/entity"
func (s *httpEntityStore) RegisterHTTPRoutes(route routing.RouteRegister) {
// For now, require admin for everything
reqGrafanaAdmin := middleware.ReqSignedIn //.ReqGrafanaAdmin
// Every * must parse to a GRN (uid+kind)
route.Get("/store/:kind/:uid", reqGrafanaAdmin, routing.Wrap(s.doGetObject))
route.Post("/store/:kind/:uid", reqGrafanaAdmin, routing.Wrap(s.doWriteObject))
route.Delete("/store/:kind/:uid", reqGrafanaAdmin, routing.Wrap(s.doDeleteObject))
route.Get("/raw/:kind/:uid", reqGrafanaAdmin, routing.Wrap(s.doGetRawObject))
route.Get("/store/:kind/:uid", reqGrafanaAdmin, routing.Wrap(s.doGetEntity))
route.Post("/store/:kind/:uid", reqGrafanaAdmin, routing.Wrap(s.doWriteEntity))
route.Delete("/store/:kind/:uid", reqGrafanaAdmin, routing.Wrap(s.doDeleteEntity))
route.Get("/raw/:kind/:uid", reqGrafanaAdmin, routing.Wrap(s.doGetRawEntity))
route.Get("/history/:kind/:uid", reqGrafanaAdmin, routing.Wrap(s.doGetHistory))
route.Get("/list/:uid", reqGrafanaAdmin, routing.Wrap(s.doListFolder)) // Simplified version of search -- path is prefix
route.Get("/search", reqGrafanaAdmin, routing.Wrap(s.doSearch))
@ -60,7 +60,7 @@ func (s *httpObjectStore) RegisterHTTPRoutes(route routing.RouteRegister) {
// This function will extract UID+Kind from the requested path "*" in our router
// This is far from ideal! but is at least consistent for these endpoints.
// This will quickly be revisited as we explore how to encode UID+Kind in a "GRN" format
func (s *httpObjectStore) getGRNFromRequest(c *models.ReqContext) (*object.GRN, map[string]string, error) {
func (s *httpEntityStore) getGRNFromRequest(c *models.ReqContext) (*entity.GRN, map[string]string, error) {
params := web.Params(c.Req)
// Read parameters that are encoded in the URL
vals := c.Req.URL.Query()
@ -69,38 +69,38 @@ func (s *httpObjectStore) getGRNFromRequest(c *models.ReqContext) (*object.GRN,
params[k] = v[0]
}
}
return &object.GRN{
return &entity.GRN{
TenantId: c.OrgID,
Kind: params[":kind"],
UID: params[":uid"],
}, params, nil
}
func (s *httpObjectStore) doGetObject(c *models.ReqContext) response.Response {
func (s *httpEntityStore) doGetEntity(c *models.ReqContext) response.Response {
grn, params, err := s.getGRNFromRequest(c)
if err != nil {
return response.Error(400, err.Error(), err)
}
rsp, err := s.store.Read(c.Req.Context(), &object.ReadObjectRequest{
rsp, err := s.store.Read(c.Req.Context(), &entity.ReadEntityRequest{
GRN: grn,
Version: params["version"], // ?version = XYZ
WithBody: params["body"] != "false", // default to true
WithSummary: params["summary"] == "true", // default to false
})
if err != nil {
return response.Error(500, "error fetching object", err)
return response.Error(500, "error fetching entity", err)
}
if rsp.Object == nil {
if rsp.Entity == nil {
return response.Error(404, "not found", nil)
}
// Configure etag support
currentEtag := rsp.Object.ETag
currentEtag := rsp.Entity.ETag
previousEtag := c.Req.Header.Get("If-None-Match")
if previousEtag == currentEtag {
return response.CreateNormalResponse(
http.Header{
"ETag": []string{rsp.Object.ETag},
"ETag": []string{rsp.Entity.ETag},
},
[]byte{}, // nothing
http.StatusNotModified, // 304
@ -111,12 +111,12 @@ func (s *httpObjectStore) doGetObject(c *models.ReqContext) response.Response {
return response.JSON(200, rsp)
}
func (s *httpObjectStore) doGetRawObject(c *models.ReqContext) response.Response {
func (s *httpEntityStore) doGetRawEntity(c *models.ReqContext) response.Response {
grn, params, err := s.getGRNFromRequest(c)
if err != nil {
return response.Error(400, err.Error(), err)
}
rsp, err := s.store.Read(c.Req.Context(), &object.ReadObjectRequest{
rsp, err := s.store.Read(c.Req.Context(), &entity.ReadEntityRequest{
GRN: grn,
Version: params["version"], // ?version = XYZ
WithBody: true,
@ -130,14 +130,14 @@ func (s *httpObjectStore) doGetRawObject(c *models.ReqContext) response.Response
return response.Error(400, "Unsupported kind", err)
}
if rsp.Object != nil && rsp.Object.Body != nil {
if rsp.Entity != nil && rsp.Entity.Body != nil {
// Configure etag support
currentEtag := rsp.Object.ETag
currentEtag := rsp.Entity.ETag
previousEtag := c.Req.Header.Get("If-None-Match")
if previousEtag == currentEtag {
return response.CreateNormalResponse(
http.Header{
"ETag": []string{rsp.Object.ETag},
"ETag": []string{rsp.Entity.ETag},
},
[]byte{}, // nothing
http.StatusNotModified, // 304
@ -152,7 +152,7 @@ func (s *httpObjectStore) doGetRawObject(c *models.ReqContext) response.Response
"Content-Type": []string{mime},
"ETag": []string{currentEtag},
},
rsp.Object.Body,
rsp.Entity.Body,
200,
)
}
@ -161,7 +161,7 @@ func (s *httpObjectStore) doGetRawObject(c *models.ReqContext) response.Response
const MAX_UPLOAD_SIZE = 5 * 1024 * 1024 // 5MB
func (s *httpObjectStore) doWriteObject(c *models.ReqContext) response.Response {
func (s *httpEntityStore) doWriteEntity(c *models.ReqContext) response.Response {
grn, params, err := s.getGRNFromRequest(c)
if err != nil {
return response.Error(400, err.Error(), err)
@ -174,7 +174,7 @@ func (s *httpObjectStore) doWriteObject(c *models.ReqContext) response.Response
return response.Error(400, "error reading body", err)
}
rsp, err := s.store.Write(c.Req.Context(), &object.WriteObjectRequest{
rsp, err := s.store.Write(c.Req.Context(), &entity.WriteEntityRequest{
GRN: grn,
Body: b,
Folder: params["folder"],
@ -187,12 +187,12 @@ func (s *httpObjectStore) doWriteObject(c *models.ReqContext) response.Response
return response.JSON(200, rsp)
}
func (s *httpObjectStore) doDeleteObject(c *models.ReqContext) response.Response {
func (s *httpEntityStore) doDeleteEntity(c *models.ReqContext) response.Response {
grn, params, err := s.getGRNFromRequest(c)
if err != nil {
return response.Error(400, err.Error(), err)
}
rsp, err := s.store.Delete(c.Req.Context(), &object.DeleteObjectRequest{
rsp, err := s.store.Delete(c.Req.Context(), &entity.DeleteEntityRequest{
GRN: grn,
PreviousVersion: params["previousVersion"],
})
@ -202,13 +202,13 @@ func (s *httpObjectStore) doDeleteObject(c *models.ReqContext) response.Response
return response.JSON(200, rsp)
}
func (s *httpObjectStore) doGetHistory(c *models.ReqContext) response.Response {
func (s *httpEntityStore) doGetHistory(c *models.ReqContext) response.Response {
grn, params, err := s.getGRNFromRequest(c)
if err != nil {
return response.Error(400, err.Error(), err)
}
limit := int64(20) // params
rsp, err := s.store.History(c.Req.Context(), &object.ObjectHistoryRequest{
rsp, err := s.store.History(c.Req.Context(), &entity.EntityHistoryRequest{
GRN: grn,
Limit: limit,
NextPageToken: params["nextPageToken"],
@ -219,7 +219,7 @@ func (s *httpObjectStore) doGetHistory(c *models.ReqContext) response.Response {
return response.JSON(200, rsp)
}
func (s *httpObjectStore) doUpload(c *models.ReqContext) response.Response {
func (s *httpEntityStore) doUpload(c *models.ReqContext) response.Response {
c.Req.Body = http.MaxBytesReader(c.Resp, c.Req.Body, MAX_UPLOAD_SIZE)
if err := c.Req.ParseMultipartForm(MAX_UPLOAD_SIZE); err != nil {
msg := fmt.Sprintf("Please limit file uploaded under %s", util.ByteCountSI(MAX_UPLOAD_SIZE))
@ -230,7 +230,7 @@ func (s *httpObjectStore) doUpload(c *models.ReqContext) response.Response {
return response.Error(400, "missing files", nil)
}
var rsp []*object.WriteObjectResponse
var rsp []*entity.WriteEntityResponse
message := getMultipartFormValue(c.Req, "message")
overwriteExistingFile := getMultipartFormValue(c.Req, "overwriteExistingFile") != "false" // must explicitly overwrite
@ -264,14 +264,14 @@ func (s *httpObjectStore) doUpload(c *models.ReqContext) response.Response {
return response.Error(500, "Internal Server Error", err)
}
grn := &object.GRN{
grn := &entity.GRN{
UID: uid,
Kind: kind.ID,
TenantId: c.OrgID,
}
if !overwriteExistingFile {
result, err := s.store.Read(ctx, &object.ReadObjectRequest{
result, err := s.store.Read(ctx, &entity.ReadEntityRequest{
GRN: grn,
WithBody: false,
WithSummary: false,
@ -279,12 +279,12 @@ func (s *httpObjectStore) doUpload(c *models.ReqContext) response.Response {
if err != nil {
return response.Error(500, "Internal Server Error", err)
}
if result.Object != nil {
if result.Entity != nil {
return response.Error(400, "File name already in use", err)
}
}
result, err := s.store.Write(ctx, &object.WriteObjectRequest{
result, err := s.store.Write(ctx, &entity.WriteEntityRequest{
GRN: grn,
Body: data,
Comment: message,
@ -302,14 +302,14 @@ func (s *httpObjectStore) doUpload(c *models.ReqContext) response.Response {
return response.JSON(200, rsp)
}
func (s *httpObjectStore) doListFolder(c *models.ReqContext) response.Response {
func (s *httpEntityStore) doListFolder(c *models.ReqContext) response.Response {
return response.JSON(501, "Not implemented yet")
}
func (s *httpObjectStore) doSearch(c *models.ReqContext) response.Response {
func (s *httpEntityStore) doSearch(c *models.ReqContext) response.Response {
vals := c.Req.URL.Query()
req := &object.ObjectSearchRequest{
req := &entity.EntitySearchRequest{
WithBody: asBoolean("body", vals, false),
WithLabels: asBoolean("labels", vals, true),
WithFields: asBoolean("fields", vals, true),

View File

@ -1,4 +1,4 @@
package object
package entity
import (
"encoding/base64"
@ -10,12 +10,12 @@ import (
)
func init() { //nolint:gochecknoinits
jsoniter.RegisterTypeEncoder("object.ObjectSearchResult", &searchResultCodec{})
jsoniter.RegisterTypeEncoder("object.WriteObjectResponse", &writeResponseCodec{})
jsoniter.RegisterTypeEncoder("object.ReadObjectResponse", &readResponseCodec{})
jsoniter.RegisterTypeEncoder("entity.EntitySearchResult", &searchResultCodec{})
jsoniter.RegisterTypeEncoder("entity.WriteObjectResponse", &writeResponseCodec{})
jsoniter.RegisterTypeEncoder("entity.ReadEntityResponse", &readResponseCodec{})
jsoniter.RegisterTypeEncoder("object.RawObject", &rawObjectCodec{})
jsoniter.RegisterTypeDecoder("object.RawObject", &rawObjectCodec{})
jsoniter.RegisterTypeEncoder("entity.Entity", &rawEntityCodec{})
jsoniter.RegisterTypeDecoder("entity.Entity", &rawEntityCodec{})
}
func writeRawJson(stream *jsoniter.Stream, val []byte) {
@ -27,30 +27,30 @@ func writeRawJson(stream *jsoniter.Stream, val []byte) {
}
// Unlike the standard JSON marshal, this will write bytes as JSON when it can
type rawObjectCodec struct{}
type rawEntityCodec struct{}
func (obj *RawObject) MarshalJSON() ([]byte, error) {
func (obj *Entity) MarshalJSON() ([]byte, error) {
var json = jsoniter.ConfigCompatibleWithStandardLibrary
return json.Marshal(obj)
}
// UnmarshalJSON will read JSON into a RawObject
func (obj *RawObject) UnmarshalJSON(b []byte) error {
// UnmarshalJSON will read JSON into a Entity
func (obj *Entity) UnmarshalJSON(b []byte) error {
if obj == nil {
return fmt.Errorf("unexpected nil for raw objcet")
}
iter := jsoniter.ParseBytes(jsoniter.ConfigDefault, b)
readRawObject(iter, obj)
readEntity(iter, obj)
return iter.Error
}
func (codec *rawObjectCodec) IsEmpty(ptr unsafe.Pointer) bool {
f := (*RawObject)(ptr)
func (codec *rawEntityCodec) IsEmpty(ptr unsafe.Pointer) bool {
f := (*Entity)(ptr)
return f.GRN == nil && f.Body == nil
}
func (codec *rawObjectCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
obj := (*RawObject)(ptr)
func (codec *rawEntityCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
obj := (*Entity)(ptr)
stream.WriteObjectStart()
stream.WriteObjectField("GRN")
stream.WriteVal(obj.GRN)
@ -121,13 +121,13 @@ func (codec *rawObjectCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream)
stream.WriteObjectEnd()
}
func (codec *rawObjectCodec) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
*(*RawObject)(ptr) = RawObject{}
raw := (*RawObject)(ptr)
readRawObject(iter, raw)
func (codec *rawEntityCodec) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
*(*Entity)(ptr) = Entity{}
raw := (*Entity)(ptr)
readEntity(iter, raw)
}
func readRawObject(iter *jsoniter.Iterator, raw *RawObject) {
func readEntity(iter *jsoniter.Iterator, raw *Entity) {
for l1Field := iter.ReadObject(); l1Field != ""; l1Field = iter.ReadObject() {
switch l1Field {
case "GRN":
@ -152,7 +152,7 @@ func readRawObject(iter *jsoniter.Iterator, raw *RawObject) {
case "version":
raw.Version = iter.ReadString()
case "origin":
raw.Origin = &ObjectOriginInfo{}
raw.Origin = &EntityOriginInfo{}
iter.ReadVal(raw.Origin)
case "body":
@ -160,7 +160,7 @@ func readRawObject(iter *jsoniter.Iterator, raw *RawObject) {
iter.ReadVal(&val) // ??? is there a smarter way to just keep the underlying bytes without read+marshal
body, err := json.Marshal(val)
if err != nil {
iter.ReportError("raw object", "error creating json from body")
iter.ReportError("raw entity", "error creating json from body")
return
}
raw.Body = body
@ -169,7 +169,7 @@ func readRawObject(iter *jsoniter.Iterator, raw *RawObject) {
val := iter.ReadString()
body, err := base64.StdEncoding.DecodeString(val)
if err != nil {
iter.ReportError("raw object", "error decoding base64 body")
iter.ReportError("raw entity", "error decoding base64 body")
return
}
raw.Body = body
@ -184,21 +184,21 @@ func readRawObject(iter *jsoniter.Iterator, raw *RawObject) {
// Unlike the standard JSON marshal, this will write bytes as JSON when it can
type readResponseCodec struct{}
func (obj *ReadObjectResponse) MarshalJSON() ([]byte, error) {
func (obj *ReadEntityResponse) MarshalJSON() ([]byte, error) {
var json = jsoniter.ConfigCompatibleWithStandardLibrary
return json.Marshal(obj)
}
func (codec *readResponseCodec) IsEmpty(ptr unsafe.Pointer) bool {
f := (*ReadObjectResponse)(ptr)
f := (*ReadEntityResponse)(ptr)
return f == nil
}
func (codec *readResponseCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
obj := (*ReadObjectResponse)(ptr)
obj := (*ReadEntityResponse)(ptr)
stream.WriteObjectStart()
stream.WriteObjectField("object")
stream.WriteVal(obj.Object)
stream.WriteObjectField("entity")
stream.WriteVal(obj.Entity)
if len(obj.SummaryJson) > 0 {
stream.WriteMore()
@ -212,18 +212,18 @@ func (codec *readResponseCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stre
// Unlike the standard JSON marshal, this will write bytes as JSON when it can
type searchResultCodec struct{}
func (obj *ObjectSearchResult) MarshalJSON() ([]byte, error) {
func (obj *EntitySearchResult) MarshalJSON() ([]byte, error) {
var json = jsoniter.ConfigCompatibleWithStandardLibrary
return json.Marshal(obj)
}
func (codec *searchResultCodec) IsEmpty(ptr unsafe.Pointer) bool {
f := (*ObjectSearchResult)(ptr)
f := (*EntitySearchResult)(ptr)
return f.GRN == nil && f.Body == nil
}
func (codec *searchResultCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
obj := (*ObjectSearchResult)(ptr)
obj := (*EntitySearchResult)(ptr)
stream.WriteObjectStart()
stream.WriteObjectField("GRN")
stream.WriteVal(obj.GRN)
@ -285,18 +285,18 @@ func (codec *searchResultCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stre
// Unlike the standard JSON marshal, this will write bytes as JSON when it can
type writeResponseCodec struct{}
func (obj *WriteObjectResponse) MarshalJSON() ([]byte, error) {
func (obj *WriteEntityResponse) MarshalJSON() ([]byte, error) {
var json = jsoniter.ConfigCompatibleWithStandardLibrary
return json.Marshal(obj)
}
func (codec *writeResponseCodec) IsEmpty(ptr unsafe.Pointer) bool {
f := (*WriteObjectResponse)(ptr)
f := (*WriteEntityResponse)(ptr)
return f == nil
}
func (codec *writeResponseCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
obj := (*WriteObjectResponse)(ptr)
obj := (*WriteEntityResponse)(ptr)
stream.WriteObjectStart()
stream.WriteObjectField("status")
stream.WriteString(obj.Status.String())
@ -311,10 +311,10 @@ func (codec *writeResponseCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Str
stream.WriteObjectField("GRN")
stream.WriteVal(obj.GRN)
}
if obj.Object != nil {
if obj.Entity != nil {
stream.WriteMore()
stream.WriteObjectField("object")
stream.WriteVal(obj.Object)
stream.WriteObjectField("entity")
stream.WriteVal(obj.Entity)
}
if len(obj.SummaryJson) > 0 {
stream.WriteMore()

View File

@ -1,4 +1,4 @@
package object
package entity
import (
"encoding/json"
@ -14,7 +14,7 @@ func TestRawEncoders(t *testing.T) {
})
require.NoError(t, err)
raw := &RawObject{
raw := &Entity{
GRN: &GRN{
UID: "a",
Kind: "b",
@ -42,7 +42,7 @@ func TestRawEncoders(t *testing.T) {
"etag": "d"
}`, str)
copy := &RawObject{}
copy := &Entity{}
err = json.Unmarshal(b, copy)
require.NoError(t, err)
}

View File

@ -15,35 +15,35 @@ import (
"github.com/grafana/grafana/pkg/services/grpcserver"
"github.com/grafana/grafana/pkg/services/sqlstore/session"
"github.com/grafana/grafana/pkg/services/store"
"github.com/grafana/grafana/pkg/services/store/entity"
"github.com/grafana/grafana/pkg/services/store/kind"
"github.com/grafana/grafana/pkg/services/store/object"
"github.com/grafana/grafana/pkg/services/store/resolver"
"github.com/grafana/grafana/pkg/setting"
)
// Make sure we implement both store + admin
var _ object.ObjectStoreServer = &sqlObjectServer{}
var _ object.ObjectStoreAdminServer = &sqlObjectServer{}
var _ entity.EntityStoreServer = &sqlEntityServer{}
var _ entity.EntityStoreAdminServer = &sqlEntityServer{}
func ProvideSQLObjectServer(db db.DB, cfg *setting.Cfg, grpcServerProvider grpcserver.Provider, kinds kind.KindRegistry, resolver resolver.ObjectReferenceResolver) object.ObjectStoreServer {
objectServer := &sqlObjectServer{
func ProvideSQLEntityServer(db db.DB, cfg *setting.Cfg, grpcServerProvider grpcserver.Provider, kinds kind.KindRegistry, resolver resolver.EntityReferenceResolver) entity.EntityStoreServer {
entityServer := &sqlEntityServer{
sess: db.GetSqlxSession(),
log: log.New("sql-object-server"),
log: log.New("sql-entity-server"),
kinds: kinds,
resolver: resolver,
}
object.RegisterObjectStoreServer(grpcServerProvider.GetServer(), objectServer)
return objectServer
entity.RegisterEntityStoreServer(grpcServerProvider.GetServer(), entityServer)
return entityServer
}
type sqlObjectServer struct {
type sqlEntityServer struct {
log log.Logger
sess *session.SessionDB
kinds kind.KindRegistry
resolver resolver.ObjectReferenceResolver
resolver resolver.EntityReferenceResolver
}
func getReadSelect(r *object.ReadObjectRequest) string {
func getReadSelect(r *entity.ReadEntityRequest) string {
fields := []string{
"tenant_id", "kind", "uid", // The PK
"version", "slug", "folder",
@ -61,10 +61,10 @@ func getReadSelect(r *object.ReadObjectRequest) string {
return "SELECT " + strings.Join(fields, ",") + " FROM entity WHERE "
}
func (s *sqlObjectServer) rowToReadObjectResponse(ctx context.Context, rows *sql.Rows, r *object.ReadObjectRequest) (*object.ReadObjectResponse, error) {
raw := &object.RawObject{
GRN: &object.GRN{},
Origin: &object.ObjectOriginInfo{},
func (s *sqlEntityServer) rowToReadEntityResponse(ctx context.Context, rows *sql.Rows, r *entity.ReadEntityRequest) (*entity.ReadEntityResponse, error) {
raw := &entity.Entity{
GRN: &entity.GRN{},
Origin: &entity.EntityOriginInfo{},
}
slug := ""
@ -93,12 +93,12 @@ func (s *sqlObjectServer) rowToReadObjectResponse(ctx context.Context, rows *sql
raw.Origin = nil
}
rsp := &object.ReadObjectResponse{
Object: raw,
rsp := &entity.ReadEntityResponse{
Entity: raw,
}
if r.WithSummary || summaryjson.errors != nil {
summary, err := summaryjson.toObjectSummary()
summary, err := summaryjson.toEntitySummary()
if err != nil {
return nil, err
}
@ -112,7 +112,7 @@ func (s *sqlObjectServer) rowToReadObjectResponse(ctx context.Context, rows *sql
return rsp, nil
}
func (s *sqlObjectServer) validateGRN(ctx context.Context, grn *object.GRN) (*object.GRN, error) {
func (s *sqlEntityServer) validateGRN(ctx context.Context, grn *entity.GRN) (*entity.GRN, error) {
if grn == nil {
return nil, fmt.Errorf("missing GRN")
}
@ -138,7 +138,7 @@ func (s *sqlObjectServer) validateGRN(ctx context.Context, grn *object.GRN) (*ob
return grn, nil
}
func (s *sqlObjectServer) Read(ctx context.Context, r *object.ReadObjectRequest) (*object.ReadObjectResponse, error) {
func (s *sqlEntityServer) Read(ctx context.Context, r *entity.ReadEntityRequest) (*entity.ReadEntityResponse, error) {
if r.Version != "" {
return s.readFromHistory(ctx, r)
}
@ -157,13 +157,13 @@ func (s *sqlObjectServer) Read(ctx context.Context, r *object.ReadObjectRequest)
defer func() { _ = rows.Close() }()
if !rows.Next() {
return &object.ReadObjectResponse{}, nil
return &entity.ReadEntityResponse{}, nil
}
return s.rowToReadObjectResponse(ctx, rows, r)
return s.rowToReadEntityResponse(ctx, rows, r)
}
func (s *sqlObjectServer) readFromHistory(ctx context.Context, r *object.ReadObjectRequest) (*object.ReadObjectResponse, error) {
func (s *sqlEntityServer) readFromHistory(ctx context.Context, r *entity.ReadEntityRequest) (*entity.ReadEntityResponse, error) {
grn, err := s.validateGRN(ctx, r.GRN)
if err != nil {
return nil, err
@ -185,14 +185,14 @@ func (s *sqlObjectServer) readFromHistory(ctx context.Context, r *object.ReadObj
// Version or key not found
if !rows.Next() {
return &object.ReadObjectResponse{}, nil
return &entity.ReadEntityResponse{}, nil
}
raw := &object.RawObject{
raw := &entity.Entity{
GRN: r.GRN,
}
rsp := &object.ReadObjectResponse{
Object: raw,
rsp := &entity.ReadEntityResponse{
Entity: raw,
}
err = rows.Scan(&raw.Body, &raw.Size, &raw.ETag, &raw.UpdatedAt, &raw.UpdatedBy)
if err != nil {
@ -220,13 +220,13 @@ func (s *sqlObjectServer) readFromHistory(ctx context.Context, r *object.ReadObj
// Clear the body if not requested
if !r.WithBody {
rsp.Object.Body = nil
rsp.Entity.Body = nil
}
return rsp, err
}
func (s *sqlObjectServer) BatchRead(ctx context.Context, b *object.BatchReadObjectRequest) (*object.BatchReadObjectResponse, error) {
func (s *sqlEntityServer) BatchRead(ctx context.Context, b *entity.BatchReadEntityRequest) (*entity.BatchReadEntityResponse, error) {
if len(b.Batch) < 1 {
return nil, fmt.Errorf("missing querires")
}
@ -262,9 +262,9 @@ func (s *sqlObjectServer) BatchRead(ctx context.Context, b *object.BatchReadObje
defer func() { _ = rows.Close() }()
// TODO? make sure the results are in order?
rsp := &object.BatchReadObjectResponse{}
rsp := &entity.BatchReadEntityResponse{}
for rows.Next() {
r, err := s.rowToReadObjectResponse(ctx, rows, req)
r, err := s.rowToReadEntityResponse(ctx, rows, req)
if err != nil {
return nil, err
}
@ -273,12 +273,12 @@ func (s *sqlObjectServer) BatchRead(ctx context.Context, b *object.BatchReadObje
return rsp, nil
}
func (s *sqlObjectServer) Write(ctx context.Context, r *object.WriteObjectRequest) (*object.WriteObjectResponse, error) {
return s.AdminWrite(ctx, object.ToAdminWriteObjectRequest(r))
func (s *sqlEntityServer) Write(ctx context.Context, r *entity.WriteEntityRequest) (*entity.WriteEntityResponse, error) {
return s.AdminWrite(ctx, entity.ToAdminWriteEntityRequest(r))
}
//nolint:gocyclo
func (s *sqlObjectServer) AdminWrite(ctx context.Context, r *object.AdminWriteObjectRequest) (*object.WriteObjectResponse, error) {
func (s *sqlEntityServer) AdminWrite(ctx context.Context, r *entity.AdminWriteEntityRequest) (*entity.WriteEntityResponse, error) {
grn, err := s.validateGRN(ctx, r.GRN)
if err != nil {
return nil, err
@ -313,17 +313,17 @@ func (s *sqlObjectServer) AdminWrite(ctx context.Context, r *object.AdminWriteOb
slug := slugify.Slugify(t)
etag := createContentsHash(body)
rsp := &object.WriteObjectResponse{
rsp := &entity.WriteEntityResponse{
GRN: grn,
Status: object.WriteObjectResponse_CREATED, // Will be changed if not true
Status: entity.WriteEntityResponse_CREATED, // Will be changed if not true
}
origin := r.Origin
if origin == nil {
origin = &object.ObjectOriginInfo{}
origin = &entity.EntityOriginInfo{}
}
err = s.sess.WithTransaction(ctx, func(tx *session.SessionTx) error {
var versionInfo *object.ObjectVersionInfo
var versionInfo *entity.EntityVersionInfo
isUpdate := false
if r.ClearHistory {
// Optionally keep the original creation time information
@ -337,7 +337,7 @@ func (s *sqlObjectServer) AdminWrite(ctx context.Context, r *object.AdminWriteOb
if err != nil {
return err
}
versionInfo = &object.ObjectVersionInfo{}
versionInfo = &entity.EntityVersionInfo{}
} else {
versionInfo, err = s.selectForUpdate(ctx, tx, oid)
if err != nil {
@ -345,10 +345,10 @@ func (s *sqlObjectServer) AdminWrite(ctx context.Context, r *object.AdminWriteOb
}
}
// Same object
// Same entity
if versionInfo.ETag == etag {
rsp.Object = versionInfo
rsp.Status = object.WriteObjectResponse_UNCHANGED
rsp.Entity = versionInfo
rsp.Status = entity.WriteEntityResponse_UNCHANGED
return nil
}
@ -436,10 +436,10 @@ func (s *sqlObjectServer) AdminWrite(ctx context.Context, r *object.AdminWriteOb
}
}
// 5. Add/update the main `object` table
rsp.Object = versionInfo
// 5. Add/update the main `entity` table
rsp.Entity = versionInfo
if isUpdate {
rsp.Status = object.WriteObjectResponse_UPDATED
rsp.Status = entity.WriteEntityResponse_UPDATED
_, err = tx.Exec(ctx, "UPDATE entity SET "+
"body=?, size=?, etag=?, version=?, "+
"updated_at=?, updated_by=?,"+
@ -488,12 +488,12 @@ func (s *sqlObjectServer) AdminWrite(ctx context.Context, r *object.AdminWriteOb
})
rsp.SummaryJson = summary.marshaled
if err != nil {
rsp.Status = object.WriteObjectResponse_ERROR
rsp.Status = entity.WriteEntityResponse_ERROR
}
return rsp, err
}
func (s *sqlObjectServer) fillCreationInfo(ctx context.Context, tx *session.SessionTx, grn string, createdAt *int64, createdBy *string) error {
func (s *sqlEntityServer) fillCreationInfo(ctx context.Context, tx *session.SessionTx, grn string, createdAt *int64, createdBy *string) error {
if *createdAt > 1000 {
ignore := int64(0)
createdAt = &ignore
@ -515,7 +515,7 @@ func (s *sqlObjectServer) fillCreationInfo(ctx context.Context, tx *session.Sess
return err
}
func (s *sqlObjectServer) selectForUpdate(ctx context.Context, tx *session.SessionTx, grn string) (*object.ObjectVersionInfo, error) {
func (s *sqlEntityServer) selectForUpdate(ctx context.Context, tx *session.SessionTx, grn string) (*entity.EntityVersionInfo, error) {
q := "SELECT etag,version,updated_at,size FROM entity WHERE grn=?"
if false { // TODO, MYSQL/PosgreSQL can lock the row " FOR UPDATE"
q += " FOR UPDATE"
@ -524,7 +524,7 @@ func (s *sqlObjectServer) selectForUpdate(ctx context.Context, tx *session.Sessi
if err != nil {
return nil, err
}
current := &object.ObjectVersionInfo{}
current := &entity.EntityVersionInfo{}
if rows.Next() {
err = rows.Scan(&current.ETag, &current.Version, &current.UpdatedAt, &current.Size)
}
@ -534,7 +534,7 @@ func (s *sqlObjectServer) selectForUpdate(ctx context.Context, tx *session.Sessi
return current, err
}
func (s *sqlObjectServer) prepare(ctx context.Context, r *object.AdminWriteObjectRequest) (*summarySupport, []byte, error) {
func (s *sqlEntityServer) prepare(ctx context.Context, r *entity.AdminWriteEntityRequest) (*summarySupport, []byte, error) {
grn := r.GRN
builder := s.kinds.GetSummaryBuilder(grn.Kind)
if builder == nil {
@ -553,13 +553,13 @@ func (s *sqlObjectServer) prepare(ctx context.Context, r *object.AdminWriteObjec
return summaryjson, body, nil
}
func (s *sqlObjectServer) Delete(ctx context.Context, r *object.DeleteObjectRequest) (*object.DeleteObjectResponse, error) {
func (s *sqlEntityServer) Delete(ctx context.Context, r *entity.DeleteEntityRequest) (*entity.DeleteEntityResponse, error) {
grn, err := s.validateGRN(ctx, r.GRN)
if err != nil {
return nil, err
}
rsp := &object.DeleteObjectResponse{}
rsp := &entity.DeleteEntityResponse{}
err = s.sess.WithTransaction(ctx, func(tx *session.SessionTx) error {
rsp.OK, err = doDelete(ctx, tx, grn.ToGRNString())
return err
@ -584,7 +584,7 @@ func doDelete(ctx context.Context, tx *session.SessionTx, grn string) (bool, err
return rows > 0, err
}
func (s *sqlObjectServer) History(ctx context.Context, r *object.ObjectHistoryRequest) (*object.ObjectHistoryResponse, error) {
func (s *sqlEntityServer) History(ctx context.Context, r *entity.EntityHistoryRequest) (*entity.EntityHistoryResponse, error) {
grn, err := s.validateGRN(ctx, r.GRN)
if err != nil {
return nil, err
@ -609,11 +609,11 @@ func (s *sqlObjectServer) History(ctx context.Context, r *object.ObjectHistoryRe
return nil, err
}
defer func() { _ = rows.Close() }()
rsp := &object.ObjectHistoryResponse{
rsp := &entity.EntityHistoryResponse{
GRN: r.GRN,
}
for rows.Next() {
v := &object.ObjectVersionInfo{}
v := &entity.EntityVersionInfo{}
err := rows.Scan(&v.Version, &v.Size, &v.ETag, &v.UpdatedAt, &v.UpdatedBy, &v.Comment)
if err != nil {
return nil, err
@ -623,7 +623,7 @@ func (s *sqlObjectServer) History(ctx context.Context, r *object.ObjectHistoryRe
return rsp, err
}
func (s *sqlObjectServer) Search(ctx context.Context, r *object.ObjectSearchRequest) (*object.ObjectSearchResponse, error) {
func (s *sqlEntityServer) Search(ctx context.Context, r *entity.EntitySearchRequest) (*entity.EntitySearchResponse, error) {
user := store.UserFromContext(ctx)
if user == nil {
return nil, fmt.Errorf("missing user in context")
@ -681,10 +681,10 @@ func (s *sqlObjectServer) Search(ctx context.Context, r *object.ObjectSearchRequ
}
defer func() { _ = rows.Close() }()
oid := ""
rsp := &object.ObjectSearchResponse{}
rsp := &entity.EntitySearchResponse{}
for rows.Next() {
result := &object.ObjectSearchResult{
GRN: &object.GRN{},
result := &entity.EntitySearchResult{
GRN: &entity.GRN{},
}
summaryjson := summarySupport{}

View File

@ -7,7 +7,7 @@ import (
)
type summarySupport struct {
model *models.ObjectSummary
model *models.EntitySummary
name string
description *string // null or empty
labels *string
@ -16,7 +16,7 @@ type summarySupport struct {
marshaled []byte
}
func newSummarySupport(summary *models.ObjectSummary) (*summarySupport, error) {
func newSummarySupport(summary *models.EntitySummary) (*summarySupport, error) {
var err error
var js []byte
s := &summarySupport{
@ -63,9 +63,9 @@ func newSummarySupport(summary *models.ObjectSummary) (*summarySupport, error) {
return s, err
}
func (s summarySupport) toObjectSummary() (*models.ObjectSummary, error) {
func (s summarySupport) toEntitySummary() (*models.EntitySummary, error) {
var err error
summary := &models.ObjectSummary{
summary := &models.EntitySummary{
Name: s.name,
}
if s.description != nil {

View File

@ -1,4 +1,4 @@
package object_server_tests
package entity_server_tests
import (
"context"
@ -11,7 +11,7 @@ import (
saAPI "github.com/grafana/grafana/pkg/services/serviceaccounts/api"
saTests "github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
"github.com/grafana/grafana/pkg/services/store"
"github.com/grafana/grafana/pkg/services/store/object"
"github.com/grafana/grafana/pkg/services/store/entity"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/tests/testinfra"
"github.com/stretchr/testify/require"
@ -53,7 +53,7 @@ func createServiceAccountAdminToken(t *testing.T, env *server.TestEnv) (string,
type testContext struct {
authToken string
client object.ObjectStoreClient
client entity.EntityStoreClient
user *user.SignedInUser
ctx context.Context
}
@ -80,7 +80,7 @@ func createTestContext(t *testing.T) testContext {
)
require.NoError(t, err)
client := object.NewObjectStoreClient(conn)
client := entity.NewEntityStoreClient(conn)
return testContext{
authToken: authToken,

View File

@ -1,4 +1,4 @@
package object_server_tests
package entity_server_tests
import (
"encoding/json"
@ -9,14 +9,14 @@ import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/store"
"github.com/grafana/grafana/pkg/services/store/object"
"github.com/grafana/grafana/pkg/services/store/entity"
"github.com/grafana/grafana/pkg/util"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/metadata"
)
type rawObjectMatcher struct {
grn *object.GRN
type rawEntityMatcher struct {
grn *entity.GRN
createdRange []time.Time
updatedRange []time.Time
createdBy string
@ -39,7 +39,7 @@ func timestampInRange(ts int64, tsRange []time.Time) bool {
return ts >= low && ts <= high
}
func requireObjectMatch(t *testing.T, obj *object.RawObject, m rawObjectMatcher) {
func requireEntityMatch(t *testing.T, obj *entity.Entity, m rawEntityMatcher) {
t.Helper()
require.NotNil(t, obj)
@ -87,7 +87,7 @@ func requireObjectMatch(t *testing.T, obj *object.RawObject, m rawObjectMatcher)
require.True(t, len(mismatches) == 0, mismatches)
}
func requireVersionMatch(t *testing.T, obj *object.ObjectVersionInfo, m objectVersionMatcher) {
func requireVersionMatch(t *testing.T, obj *entity.EntityVersionInfo, m objectVersionMatcher) {
t.Helper()
mismatches := ""
@ -110,7 +110,7 @@ func requireVersionMatch(t *testing.T, obj *object.ObjectVersionInfo, m objectVe
require.True(t, len(mismatches) == 0, mismatches)
}
func TestIntegrationObjectServer(t *testing.T) {
func TestIntegrationEntityServer(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
@ -121,25 +121,25 @@ func TestIntegrationObjectServer(t *testing.T) {
fakeUser := store.GetUserIDString(testCtx.user)
firstVersion := "1"
kind := models.StandardKindJSONObj
grn := &object.GRN{
grn := &entity.GRN{
Kind: kind,
UID: "my-test-entity",
}
body := []byte("{\"name\":\"John\"}")
t.Run("should not retrieve non-existent objects", func(t *testing.T) {
resp, err := testCtx.client.Read(ctx, &object.ReadObjectRequest{
resp, err := testCtx.client.Read(ctx, &entity.ReadEntityRequest{
GRN: grn,
})
require.NoError(t, err)
require.NotNil(t, resp)
require.Nil(t, resp.Object)
require.Nil(t, resp.Entity)
})
t.Run("should be able to read persisted objects", func(t *testing.T) {
before := time.Now()
writeReq := &object.WriteObjectRequest{
writeReq := &entity.WriteEntityRequest{
GRN: grn,
Body: body,
Comment: "first entity!",
@ -153,24 +153,24 @@ func TestIntegrationObjectServer(t *testing.T) {
version: &firstVersion,
comment: &writeReq.Comment,
}
requireVersionMatch(t, writeResp.Object, versionMatcher)
requireVersionMatch(t, writeResp.Entity, versionMatcher)
readResp, err := testCtx.client.Read(ctx, &object.ReadObjectRequest{
readResp, err := testCtx.client.Read(ctx, &entity.ReadEntityRequest{
GRN: grn,
Version: "",
WithBody: true,
})
require.NoError(t, err)
require.Nil(t, readResp.SummaryJson)
require.NotNil(t, readResp.Object)
require.NotNil(t, readResp.Entity)
foundGRN := readResp.Object.GRN
foundGRN := readResp.Entity.GRN
require.NotNil(t, foundGRN)
require.Equal(t, testCtx.user.OrgID, foundGRN.TenantId) // orgId becomes the tenant id when not set
require.Equal(t, grn.Kind, foundGRN.Kind)
require.Equal(t, grn.UID, foundGRN.UID)
objectMatcher := rawObjectMatcher{
objectMatcher := rawEntityMatcher{
grn: grn,
createdRange: []time.Time{before, time.Now()},
updatedRange: []time.Time{before, time.Now()},
@ -179,97 +179,97 @@ func TestIntegrationObjectServer(t *testing.T) {
body: body,
version: &firstVersion,
}
requireObjectMatch(t, readResp.Object, objectMatcher)
requireEntityMatch(t, readResp.Entity, objectMatcher)
deleteResp, err := testCtx.client.Delete(ctx, &object.DeleteObjectRequest{
deleteResp, err := testCtx.client.Delete(ctx, &entity.DeleteEntityRequest{
GRN: grn,
PreviousVersion: writeResp.Object.Version,
PreviousVersion: writeResp.Entity.Version,
})
require.NoError(t, err)
require.True(t, deleteResp.OK)
readRespAfterDelete, err := testCtx.client.Read(ctx, &object.ReadObjectRequest{
readRespAfterDelete, err := testCtx.client.Read(ctx, &entity.ReadEntityRequest{
GRN: grn,
Version: "",
WithBody: true,
})
require.NoError(t, err)
require.Nil(t, readRespAfterDelete.Object)
require.Nil(t, readRespAfterDelete.Entity)
})
t.Run("should be able to update an object", func(t *testing.T) {
before := time.Now()
grn := &object.GRN{
grn := &entity.GRN{
Kind: kind,
UID: util.GenerateShortUID(),
}
writeReq1 := &object.WriteObjectRequest{
writeReq1 := &entity.WriteEntityRequest{
GRN: grn,
Body: body,
Comment: "first entity!",
}
writeResp1, err := testCtx.client.Write(ctx, writeReq1)
require.NoError(t, err)
require.Equal(t, object.WriteObjectResponse_CREATED, writeResp1.Status)
require.Equal(t, entity.WriteEntityResponse_CREATED, writeResp1.Status)
body2 := []byte("{\"name\":\"John2\"}")
writeReq2 := &object.WriteObjectRequest{
writeReq2 := &entity.WriteEntityRequest{
GRN: grn,
Body: body2,
Comment: "update1",
}
writeResp2, err := testCtx.client.Write(ctx, writeReq2)
require.NoError(t, err)
require.NotEqual(t, writeResp1.Object.Version, writeResp2.Object.Version)
require.NotEqual(t, writeResp1.Entity.Version, writeResp2.Entity.Version)
// Duplicate write (no change)
writeDupRsp, err := testCtx.client.Write(ctx, writeReq2)
require.NoError(t, err)
require.Nil(t, writeDupRsp.Error)
require.Equal(t, object.WriteObjectResponse_UNCHANGED, writeDupRsp.Status)
require.Equal(t, writeResp2.Object.Version, writeDupRsp.Object.Version)
require.Equal(t, writeResp2.Object.ETag, writeDupRsp.Object.ETag)
require.Equal(t, entity.WriteEntityResponse_UNCHANGED, writeDupRsp.Status)
require.Equal(t, writeResp2.Entity.Version, writeDupRsp.Entity.Version)
require.Equal(t, writeResp2.Entity.ETag, writeDupRsp.Entity.ETag)
body3 := []byte("{\"name\":\"John3\"}")
writeReq3 := &object.WriteObjectRequest{
writeReq3 := &entity.WriteEntityRequest{
GRN: grn,
Body: body3,
Comment: "update3",
}
writeResp3, err := testCtx.client.Write(ctx, writeReq3)
require.NoError(t, err)
require.NotEqual(t, writeResp3.Object.Version, writeResp2.Object.Version)
require.NotEqual(t, writeResp3.Entity.Version, writeResp2.Entity.Version)
latestMatcher := rawObjectMatcher{
latestMatcher := rawEntityMatcher{
grn: grn,
createdRange: []time.Time{before, time.Now()},
updatedRange: []time.Time{before, time.Now()},
createdBy: fakeUser,
updatedBy: fakeUser,
body: body3,
version: &writeResp3.Object.Version,
version: &writeResp3.Entity.Version,
}
readRespLatest, err := testCtx.client.Read(ctx, &object.ReadObjectRequest{
readRespLatest, err := testCtx.client.Read(ctx, &entity.ReadEntityRequest{
GRN: grn,
Version: "", // latest
WithBody: true,
})
require.NoError(t, err)
require.Nil(t, readRespLatest.SummaryJson)
requireObjectMatch(t, readRespLatest.Object, latestMatcher)
requireEntityMatch(t, readRespLatest.Entity, latestMatcher)
readRespFirstVer, err := testCtx.client.Read(ctx, &object.ReadObjectRequest{
readRespFirstVer, err := testCtx.client.Read(ctx, &entity.ReadEntityRequest{
GRN: grn,
Version: writeResp1.Object.Version,
Version: writeResp1.Entity.Version,
WithBody: true,
})
require.NoError(t, err)
require.Nil(t, readRespFirstVer.SummaryJson)
require.NotNil(t, readRespFirstVer.Object)
requireObjectMatch(t, readRespFirstVer.Object, rawObjectMatcher{
require.NotNil(t, readRespFirstVer.Entity)
requireEntityMatch(t, readRespFirstVer.Entity, rawEntityMatcher{
grn: grn,
createdRange: []time.Time{before, time.Now()},
updatedRange: []time.Time{before, time.Now()},
@ -279,19 +279,19 @@ func TestIntegrationObjectServer(t *testing.T) {
version: &firstVersion,
})
history, err := testCtx.client.History(ctx, &object.ObjectHistoryRequest{
history, err := testCtx.client.History(ctx, &entity.EntityHistoryRequest{
GRN: grn,
})
require.NoError(t, err)
require.Equal(t, []*object.ObjectVersionInfo{
writeResp3.Object,
writeResp2.Object,
writeResp1.Object,
require.Equal(t, []*entity.EntityVersionInfo{
writeResp3.Entity,
writeResp2.Entity,
writeResp1.Entity,
}, history.Versions)
deleteResp, err := testCtx.client.Delete(ctx, &object.DeleteObjectRequest{
deleteResp, err := testCtx.client.Delete(ctx, &entity.DeleteEntityRequest{
GRN: grn,
PreviousVersion: writeResp3.Object.Version,
PreviousVersion: writeResp3.Entity.Version,
})
require.NoError(t, err)
require.True(t, deleteResp.OK)
@ -302,14 +302,14 @@ func TestIntegrationObjectServer(t *testing.T) {
uid3 := "uid3"
uid4 := "uid4"
kind2 := models.StandardKindPlaylist
w1, err := testCtx.client.Write(ctx, &object.WriteObjectRequest{
w1, err := testCtx.client.Write(ctx, &entity.WriteEntityRequest{
GRN: grn,
Body: body,
})
require.NoError(t, err)
w2, err := testCtx.client.Write(ctx, &object.WriteObjectRequest{
GRN: &object.GRN{
w2, err := testCtx.client.Write(ctx, &entity.WriteEntityRequest{
GRN: &entity.GRN{
UID: uid2,
Kind: kind,
},
@ -317,8 +317,8 @@ func TestIntegrationObjectServer(t *testing.T) {
})
require.NoError(t, err)
w3, err := testCtx.client.Write(ctx, &object.WriteObjectRequest{
GRN: &object.GRN{
w3, err := testCtx.client.Write(ctx, &entity.WriteEntityRequest{
GRN: &entity.GRN{
UID: uid3,
Kind: kind2,
},
@ -326,8 +326,8 @@ func TestIntegrationObjectServer(t *testing.T) {
})
require.NoError(t, err)
w4, err := testCtx.client.Write(ctx, &object.WriteObjectRequest{
GRN: &object.GRN{
w4, err := testCtx.client.Write(ctx, &entity.WriteEntityRequest{
GRN: &entity.GRN{
UID: uid4,
Kind: kind2,
},
@ -335,7 +335,7 @@ func TestIntegrationObjectServer(t *testing.T) {
})
require.NoError(t, err)
search, err := testCtx.client.Search(ctx, &object.ObjectSearchRequest{
search, err := testCtx.client.Search(ctx, &entity.EntitySearchRequest{
Kind: []string{kind, kind2},
WithBody: false,
})
@ -353,14 +353,14 @@ func TestIntegrationObjectServer(t *testing.T) {
require.Equal(t, []string{"my-test-entity", "uid2", "uid3", "uid4"}, uids)
require.Equal(t, []string{"jsonobj", "jsonobj", "playlist", "playlist"}, kinds)
require.Equal(t, []string{
w1.Object.Version,
w2.Object.Version,
w3.Object.Version,
w4.Object.Version,
w1.Entity.Version,
w2.Entity.Version,
w3.Entity.Version,
w4.Entity.Version,
}, version)
// Again with only one kind
searchKind1, err := testCtx.client.Search(ctx, &object.ObjectSearchRequest{
searchKind1, err := testCtx.client.Search(ctx, &entity.EntitySearchRequest{
Kind: []string{kind},
})
require.NoError(t, err)
@ -375,8 +375,8 @@ func TestIntegrationObjectServer(t *testing.T) {
require.Equal(t, []string{"my-test-entity", "uid2"}, uids)
require.Equal(t, []string{"jsonobj", "jsonobj"}, kinds)
require.Equal(t, []string{
w1.Object.Version,
w2.Object.Version,
w1.Entity.Version,
w2.Entity.Version,
}, version)
})
}

View File

@ -1,8 +1,8 @@
package object
package entity
// The admin request is a superset of write request features
func ToAdminWriteObjectRequest(req *WriteObjectRequest) *AdminWriteObjectRequest {
return &AdminWriteObjectRequest{
func ToAdminWriteEntityRequest(req *WriteEntityRequest) *AdminWriteEntityRequest {
return &AdminWriteEntityRequest{
GRN: req.GRN,
Body: req.Body,
Folder: req.Folder,

View File

@ -13,24 +13,24 @@ type ReferenceAccumulator interface {
Add(kind string, subtype string, uid string)
// Returns the set of distinct references in a sorted order
Get() []*models.ObjectExternalReference
Get() []*models.EntityExternalReference
}
func NewReferenceAccumulator() ReferenceAccumulator {
return &referenceAccumulator{
refs: make(map[string]*models.ObjectExternalReference),
refs: make(map[string]*models.EntityExternalReference),
}
}
type referenceAccumulator struct {
refs map[string]*models.ObjectExternalReference
refs map[string]*models.EntityExternalReference
}
func (x *referenceAccumulator) Add(kind string, sub string, uid string) {
key := fmt.Sprintf("%s/%s/%s", kind, sub, uid)
_, ok := x.refs[key]
if !ok {
x.refs[key] = &models.ObjectExternalReference{
x.refs[key] = &models.EntityExternalReference{
Kind: kind,
Type: sub,
UID: uid,
@ -38,14 +38,14 @@ func (x *referenceAccumulator) Add(kind string, sub string, uid string) {
}
}
func (x *referenceAccumulator) Get() []*models.ObjectExternalReference {
func (x *referenceAccumulator) Get() []*models.EntityExternalReference {
keys := make([]string, 0, len(x.refs))
for k := range x.refs {
keys = append(keys, k)
}
sort.Strings(keys)
refs := make([]*models.ObjectExternalReference, len(keys))
refs := make([]*models.EntityExternalReference, len(keys))
for i, key := range keys {
refs[i] = x.refs[key]
}

View File

@ -12,8 +12,8 @@ import (
"github.com/grafana/grafana/pkg/plugins"
)
func GetObjectKindInfo() models.ObjectKindInfo {
return models.ObjectKindInfo{
func GetEntityKindInfo() models.EntityKindInfo {
return models.EntityKindInfo{
ID: models.StandardKindDashboard,
Name: "Dashboard",
Description: "Define a grafana dashboard layout",
@ -21,16 +21,16 @@ func GetObjectKindInfo() models.ObjectKindInfo {
}
// This summary does not resolve old name as UID
func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
func GetEntitySummaryBuilder() models.EntitySummaryBuilder {
builder := NewStaticDashboardSummaryBuilder(&directLookup{}, true)
return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
return func(ctx context.Context, uid string, body []byte) (*models.EntitySummary, []byte, error) {
return builder(ctx, uid, body)
}
}
// This implementation moves datasources referenced by internal ID or name to UID
func NewStaticDashboardSummaryBuilder(lookup DatasourceLookup, sanitize bool) models.ObjectSummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
func NewStaticDashboardSummaryBuilder(lookup DatasourceLookup, sanitize bool) models.EntitySummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.EntitySummary, []byte, error) {
var parsed map[string]interface{}
if sanitize {
@ -44,14 +44,14 @@ func NewStaticDashboardSummaryBuilder(lookup DatasourceLookup, sanitize bool) mo
// slug? (derived from title)
}
summary := &models.ObjectSummary{
summary := &models.EntitySummary{
Labels: make(map[string]string),
Fields: make(map[string]interface{}),
}
stream := bytes.NewBuffer(body)
dash, err := readDashboard(stream, lookup)
if err != nil {
summary.Error = &models.ObjectErrorInfo{
summary.Error = &models.EntityErrorInfo{
Message: err.Error(),
}
return summary, body, err
@ -72,7 +72,7 @@ func NewStaticDashboardSummaryBuilder(lookup DatasourceLookup, sanitize bool) mo
for _, panel := range dash.Panels {
panelRefs := NewReferenceAccumulator()
p := &models.ObjectSummary{
p := &models.EntitySummary{
UID: uid + "#" + strconv.FormatInt(panel.ID, 10),
Kind: "panel",
}

View File

@ -16,7 +16,7 @@ func TestReadSummaries(t *testing.T) {
devdash := "../../../../../devenv/dev-dashboards/panel-graph/"
ctx := context.Background()
reader := GetObjectSummaryBuilder()
reader := GetEntitySummaryBuilder()
failed := make([]string, 0, 10)
err := filepath.Walk(devdash,

View File

@ -9,16 +9,16 @@ import (
"github.com/grafana/grafana/pkg/services/store"
)
func GetObjectKindInfo() models.ObjectKindInfo {
return models.ObjectKindInfo{
func GetEntityKindInfo() models.EntityKindInfo {
return models.EntityKindInfo{
ID: models.StandardKindDataFrame,
Name: "Data frame",
Description: "Data frame",
}
}
func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
func GetEntitySummaryBuilder() models.EntitySummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.EntitySummary, []byte, error) {
df := &data.Frame{}
err := json.Unmarshal(body, df)
if err != nil {
@ -33,7 +33,7 @@ func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
if err != nil {
return nil, nil, err
}
summary := &models.ObjectSummary{
summary := &models.EntitySummary{
Kind: models.StandardKindDataFrame,
Name: df.Name,
UID: uid,

View File

@ -23,7 +23,7 @@ func TestDataFrameSummary(t *testing.T) {
in, err := data.FrameToJSON(df, data.IncludeAll)
require.NoError(t, err)
summary, out, err := GetObjectSummaryBuilder()(context.Background(), "somthing", in)
summary, out, err := GetEntitySummaryBuilder()(context.Background(), "somthing", in)
require.NoError(t, err)
require.Equal(t, in, out) // same json

View File

@ -8,8 +8,8 @@ import (
"github.com/grafana/grafana/pkg/models"
)
func GetObjectKindInfo(kind string) models.ObjectKindInfo {
return models.ObjectKindInfo{
func GetEntityKindInfo(kind string) models.EntityKindInfo {
return models.EntityKindInfo{
ID: kind,
Name: kind,
Description: "Dummy kind used for testing.",
@ -17,9 +17,9 @@ func GetObjectKindInfo(kind string) models.ObjectKindInfo {
}
}
func GetObjectSummaryBuilder(kind string) models.ObjectSummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
summary := &models.ObjectSummary{
func GetEntitySummaryBuilder(kind string) models.EntitySummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.EntitySummary, []byte, error) {
summary := &models.EntitySummary{
Name: fmt.Sprintf("Dummy: %s", kind),
Kind: kind,
Description: fmt.Sprintf("Wrote at %s", time.Now().Local().String()),
@ -35,7 +35,7 @@ func GetObjectSummaryBuilder(kind string) models.ObjectSummaryBuilder {
},
Error: nil, // ignore for now
Nested: nil, // ignore for now
References: []*models.ObjectExternalReference{
References: []*models.EntityExternalReference{
{
Kind: "ds",
Type: "influx",

View File

@ -13,15 +13,15 @@ type Model struct {
Description string `json:"description,omitempty"`
}
func GetObjectKindInfo() models.ObjectKindInfo {
return models.ObjectKindInfo{
func GetEntityKindInfo() models.EntityKindInfo {
return models.EntityKindInfo{
ID: models.StandardKindFolder,
Name: "Folder",
}
}
func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
func GetEntitySummaryBuilder() models.EntitySummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.EntitySummary, []byte, error) {
obj := &Model{}
err := json.Unmarshal(body, obj)
if err != nil {
@ -32,7 +32,7 @@ func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
obj.Name = store.GuessNameFromUID(uid)
}
summary := &models.ObjectSummary{
summary := &models.EntitySummary{
Kind: models.StandardKindFolder,
Name: obj.Name,
Description: obj.Description,

View File

@ -9,8 +9,8 @@ import (
"github.com/grafana/grafana/pkg/services/store"
)
func GetObjectKindInfo() models.ObjectKindInfo {
return models.ObjectKindInfo{
func GetEntityKindInfo() models.EntityKindInfo {
return models.EntityKindInfo{
ID: models.StandardKindGeoJSON,
Name: "GeoJSON",
Description: "JSON formatted spatial data",
@ -20,8 +20,8 @@ func GetObjectKindInfo() models.ObjectKindInfo {
}
// Very basic geojson validator
func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
func GetEntitySummaryBuilder() models.EntitySummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.EntitySummary, []byte, error) {
var geojson map[string]interface{}
err := json.Unmarshal(body, &geojson)
if err != nil {
@ -38,7 +38,7 @@ func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
return nil, nil, err
}
summary := &models.ObjectSummary{
summary := &models.EntitySummary{
Kind: models.StandardKindGeoJSON,
Name: store.GuessNameFromUID(uid),
UID: uid,

View File

@ -10,7 +10,7 @@ import (
)
func TestGeoJSONSummary(t *testing.T) {
builder := GetObjectSummaryBuilder()
builder := GetEntitySummaryBuilder()
geo := []byte(`{"type":"FeatureCo`) // invalid
_, _, err := builder(context.Background(), "hello", geo)
require.Error(t, err)

View File

@ -8,16 +8,16 @@ import (
"github.com/grafana/grafana/pkg/services/store"
)
func GetObjectKindInfo() models.ObjectKindInfo {
return models.ObjectKindInfo{
func GetEntityKindInfo() models.EntityKindInfo {
return models.EntityKindInfo{
ID: models.StandardKindJSONObj,
Name: "JSON Object",
Description: "JSON Object",
}
}
func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
func GetEntitySummaryBuilder() models.EntitySummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.EntitySummary, []byte, error) {
v := make(map[string]interface{})
err := json.Unmarshal(body, &v)
if err != nil {
@ -28,7 +28,7 @@ func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
if err != nil {
return nil, nil, err
}
return &models.ObjectSummary{
return &models.EntitySummary{
Kind: models.StandardKindJSONObj,
Name: store.GuessNameFromUID(uid),
UID: uid,

View File

@ -23,7 +23,7 @@ func TestDataFrameSummary(t *testing.T) {
in, err := data.FrameToJSON(df, data.IncludeAll)
require.NoError(t, err)
summary, out, err := GetObjectSummaryBuilder()(context.Background(), "path/to/item", in)
summary, out, err := GetEntitySummaryBuilder()(context.Background(), "path/to/item", in)
require.NoError(t, err)
require.JSONEq(t, string(in), string(out)) // same json

View File

@ -9,19 +9,19 @@ import (
"github.com/grafana/grafana/pkg/models"
)
func GetObjectKindInfo() models.ObjectKindInfo {
return models.ObjectKindInfo{
func GetEntityKindInfo() models.EntityKindInfo {
return models.EntityKindInfo{
ID: models.StandardKindPlaylist,
Name: "Playlist",
Description: "Cycle though a collection of dashboards automatically",
}
}
func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
func GetEntitySummaryBuilder() models.EntitySummaryBuilder {
return summaryBuilder
}
func summaryBuilder(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
func summaryBuilder(ctx context.Context, uid string, body []byte) (*models.EntitySummary, []byte, error) {
obj := &playlist.Playlist{}
err := json.Unmarshal(body, obj)
if err != nil {
@ -35,7 +35,7 @@ func summaryBuilder(ctx context.Context, uid string, body []byte) (*models.Objec
}
obj.Uid = uid // make sure they are consistent
summary := &models.ObjectSummary{
summary := &models.EntitySummary{
UID: uid,
Name: obj.Name,
Description: fmt.Sprintf("%d items, refreshed every %s", len(*obj.Items), obj.Interval),
@ -44,7 +44,7 @@ func summaryBuilder(ctx context.Context, uid string, body []byte) (*models.Objec
for _, item := range *obj.Items {
switch item.Type {
case playlist.PlaylistItemTypeDashboardByUid:
summary.References = append(summary.References, &models.ObjectExternalReference{
summary.References = append(summary.References, &models.EntityExternalReference{
Kind: "dashboard",
UID: item.Value,
})
@ -57,7 +57,7 @@ func summaryBuilder(ctx context.Context, uid string, body []byte) (*models.Objec
case playlist.PlaylistItemTypeDashboardById:
// obviously insufficient long term... but good to have an example :)
summary.Error = &models.ObjectErrorInfo{
summary.Error = &models.EntityErrorInfo{
Message: "Playlist uses deprecated internal id system",
}
}

View File

@ -10,7 +10,7 @@ import (
)
func TestPlaylistSummary(t *testing.T) {
builder := GetObjectSummaryBuilder()
builder := GetEntitySummaryBuilder()
// Do not parse invalid input
_, _, err := builder(context.Background(), "abc", []byte("{invalid json"))

View File

@ -9,8 +9,8 @@ import (
"github.com/grafana/grafana/pkg/services/store"
)
func GetObjectKindInfo() models.ObjectKindInfo {
return models.ObjectKindInfo{
func GetEntityKindInfo() models.EntityKindInfo {
return models.EntityKindInfo{
ID: models.StandardKindPNG,
Name: "PNG",
Description: "PNG Image file",
@ -21,15 +21,15 @@ func GetObjectKindInfo() models.ObjectKindInfo {
}
// SVG sanitizer based on the rendering service
func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
func GetEntitySummaryBuilder() models.EntitySummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.EntitySummary, []byte, error) {
img, err := png.Decode(bytes.NewReader(body))
if err != nil {
return nil, nil, err
}
size := img.Bounds().Size()
summary := &models.ObjectSummary{
summary := &models.EntitySummary{
Kind: models.StandardKindSVG,
Name: store.GuessNameFromUID(uid),
UID: uid,

View File

@ -14,7 +14,7 @@ func TestPNGSummary(t *testing.T) {
img, err := base64.StdEncoding.DecodeString(gopher)
require.NoError(t, err)
summary, out, err := GetObjectSummaryBuilder()(context.Background(), "hello.png", img)
summary, out, err := GetEntitySummaryBuilder()(context.Background(), "hello.png", img)
require.NoError(t, err)
require.Equal(t, img, out) // same image

View File

@ -20,46 +20,46 @@ import (
)
type KindRegistry interface {
Register(info models.ObjectKindInfo, builder models.ObjectSummaryBuilder) error
GetSummaryBuilder(kind string) models.ObjectSummaryBuilder
GetInfo(kind string) (models.ObjectKindInfo, error)
GetFromExtension(suffix string) (models.ObjectKindInfo, error)
GetKinds() []models.ObjectKindInfo
Register(info models.EntityKindInfo, builder models.EntitySummaryBuilder) error
GetSummaryBuilder(kind string) models.EntitySummaryBuilder
GetInfo(kind string) (models.EntityKindInfo, error)
GetFromExtension(suffix string) (models.EntityKindInfo, error)
GetKinds() []models.EntityKindInfo
}
func NewKindRegistry() KindRegistry {
kinds := make(map[string]*kindValues)
kinds[models.StandardKindPlaylist] = &kindValues{
info: playlist.GetObjectKindInfo(),
builder: playlist.GetObjectSummaryBuilder(),
info: playlist.GetEntityKindInfo(),
builder: playlist.GetEntitySummaryBuilder(),
}
kinds[models.StandardKindDashboard] = &kindValues{
info: dashboard.GetObjectKindInfo(),
builder: dashboard.GetObjectSummaryBuilder(),
info: dashboard.GetEntityKindInfo(),
builder: dashboard.GetEntitySummaryBuilder(),
}
kinds[models.StandardKindSnapshot] = &kindValues{
info: snapshot.GetObjectKindInfo(),
builder: snapshot.GetObjectSummaryBuilder(),
info: snapshot.GetEntityKindInfo(),
builder: snapshot.GetEntitySummaryBuilder(),
}
kinds[models.StandardKindFolder] = &kindValues{
info: folder.GetObjectKindInfo(),
builder: folder.GetObjectSummaryBuilder(),
info: folder.GetEntityKindInfo(),
builder: folder.GetEntitySummaryBuilder(),
}
kinds[models.StandardKindPNG] = &kindValues{
info: png.GetObjectKindInfo(),
builder: png.GetObjectSummaryBuilder(),
info: png.GetEntityKindInfo(),
builder: png.GetEntitySummaryBuilder(),
}
kinds[models.StandardKindGeoJSON] = &kindValues{
info: geojson.GetObjectKindInfo(),
builder: geojson.GetObjectSummaryBuilder(),
info: geojson.GetEntityKindInfo(),
builder: geojson.GetEntitySummaryBuilder(),
}
kinds[models.StandardKindDataFrame] = &kindValues{
info: dataframe.GetObjectKindInfo(),
builder: dataframe.GetObjectSummaryBuilder(),
info: dataframe.GetEntityKindInfo(),
builder: dataframe.GetEntitySummaryBuilder(),
}
kinds[models.StandardKindJSONObj] = &kindValues{
info: jsonobj.GetObjectKindInfo(),
builder: jsonobj.GetObjectSummaryBuilder(),
info: jsonobj.GetEntityKindInfo(),
builder: jsonobj.GetEntitySummaryBuilder(),
}
// create a registry
@ -77,29 +77,29 @@ func ProvideService(cfg *setting.Cfg, renderer rendering.Service) KindRegistry {
// Register SVG support
//-----------------------
info := svg.GetObjectKindInfo()
info := svg.GetEntityKindInfo()
allowUnsanitizedSvgUpload := cfg != nil && cfg.Storage.AllowUnsanitizedSvgUpload
support := svg.GetObjectSummaryBuilder(allowUnsanitizedSvgUpload, renderer)
support := svg.GetEntitySummaryBuilder(allowUnsanitizedSvgUpload, renderer)
_ = reg.Register(info, support)
return reg
}
type kindValues struct {
info models.ObjectKindInfo
builder models.ObjectSummaryBuilder
info models.EntityKindInfo
builder models.EntitySummaryBuilder
}
type registry struct {
mutex sync.RWMutex
kinds map[string]*kindValues
info []models.ObjectKindInfo
suffix map[string]models.ObjectKindInfo
info []models.EntityKindInfo
suffix map[string]models.EntityKindInfo
}
func (r *registry) updateInfoArray() {
suffix := make(map[string]models.ObjectKindInfo)
info := make([]models.ObjectKindInfo, 0, len(r.kinds))
suffix := make(map[string]models.EntityKindInfo)
info := make([]models.EntityKindInfo, 0, len(r.kinds))
for _, v := range r.kinds {
info = append(info, v.info)
if v.info.FileExtension != "" {
@ -113,7 +113,7 @@ func (r *registry) updateInfoArray() {
r.suffix = suffix
}
func (r *registry) Register(info models.ObjectKindInfo, builder models.ObjectSummaryBuilder) error {
func (r *registry) Register(info models.EntityKindInfo, builder models.EntitySummaryBuilder) error {
if info.ID == "" || builder == nil {
return fmt.Errorf("invalid kind")
}
@ -134,7 +134,7 @@ func (r *registry) Register(info models.ObjectKindInfo, builder models.ObjectSum
}
// GetSummaryBuilder returns a builder or nil if not found
func (r *registry) GetSummaryBuilder(kind string) models.ObjectSummaryBuilder {
func (r *registry) GetSummaryBuilder(kind string) models.EntitySummaryBuilder {
r.mutex.RLock()
defer r.mutex.RUnlock()
@ -146,7 +146,7 @@ func (r *registry) GetSummaryBuilder(kind string) models.ObjectSummaryBuilder {
}
// GetInfo returns the registered info
func (r *registry) GetInfo(kind string) (models.ObjectKindInfo, error) {
func (r *registry) GetInfo(kind string) (models.EntityKindInfo, error) {
r.mutex.RLock()
defer r.mutex.RUnlock()
@ -154,11 +154,11 @@ func (r *registry) GetInfo(kind string) (models.ObjectKindInfo, error) {
if ok {
return v.info, nil
}
return models.ObjectKindInfo{}, fmt.Errorf("not found")
return models.EntityKindInfo{}, fmt.Errorf("not found")
}
// GetInfo returns the registered info
func (r *registry) GetFromExtension(suffix string) (models.ObjectKindInfo, error) {
func (r *registry) GetFromExtension(suffix string) (models.EntityKindInfo, error) {
r.mutex.RLock()
defer r.mutex.RUnlock()
@ -166,11 +166,11 @@ func (r *registry) GetFromExtension(suffix string) (models.ObjectKindInfo, error
if ok {
return v, nil
}
return models.ObjectKindInfo{}, fmt.Errorf("not found")
return models.EntityKindInfo{}, fmt.Errorf("not found")
}
// GetSummaryBuilder returns a builder or nil if not found
func (r *registry) GetKinds() []models.ObjectKindInfo {
func (r *registry) GetKinds() []models.EntityKindInfo {
r.mutex.RLock()
defer r.mutex.RUnlock()

View File

@ -11,7 +11,7 @@ import (
func TestKindRegistry(t *testing.T) {
registry := NewKindRegistry()
err := registry.Register(dummy.GetObjectKindInfo("test"), dummy.GetObjectSummaryBuilder("test"))
err := registry.Register(dummy.GetEntityKindInfo("test"), dummy.GetEntitySummaryBuilder("test"))
require.NoError(t, err)
ids := []string{}

View File

@ -19,15 +19,15 @@ type Model struct {
Snapshot json.RawMessage `json:"snapshot,omitempty"`
}
func GetObjectKindInfo() models.ObjectKindInfo {
return models.ObjectKindInfo{
func GetEntityKindInfo() models.EntityKindInfo {
return models.EntityKindInfo{
ID: models.StandardKindSnapshot,
Name: "Snapshot",
}
}
func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
func GetEntitySummaryBuilder() models.EntitySummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.EntitySummary, []byte, error) {
obj := &Model{}
err := json.Unmarshal(body, obj)
if err != nil {
@ -41,7 +41,7 @@ func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
return nil, nil, fmt.Errorf("expected delete key")
}
summary := &models.ObjectSummary{
summary := &models.EntitySummary{
Kind: models.StandardKindFolder,
Name: obj.Name,
Description: obj.Description,
@ -51,7 +51,7 @@ func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
"externalURL": obj.ExternalURL,
"expires": obj.Expires,
},
References: []*models.ObjectExternalReference{
References: []*models.EntityExternalReference{
{Kind: models.StandardKindDashboard, UID: obj.DashboardUID},
},
}

View File

@ -9,8 +9,8 @@ import (
"github.com/grafana/grafana/pkg/services/rendering"
)
func GetObjectKindInfo() models.ObjectKindInfo {
return models.ObjectKindInfo{
func GetEntityKindInfo() models.EntityKindInfo {
return models.EntityKindInfo{
ID: models.StandardKindSVG,
Name: "SVG",
Description: "Scalable Vector Graphics",
@ -21,8 +21,8 @@ func GetObjectKindInfo() models.ObjectKindInfo {
}
// SVG sanitizer based on the rendering service
func GetObjectSummaryBuilder(allowUnsanitizedSvgUpload bool, renderer rendering.Service) models.ObjectSummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.ObjectSummary, []byte, error) {
func GetEntitySummaryBuilder(allowUnsanitizedSvgUpload bool, renderer rendering.Service) models.EntitySummaryBuilder {
return func(ctx context.Context, uid string, body []byte) (*models.EntitySummary, []byte, error) {
if !IsSVG(body) {
return nil, nil, fmt.Errorf("invalid svg")
}
@ -45,7 +45,7 @@ func GetObjectSummaryBuilder(allowUnsanitizedSvgUpload bool, renderer rendering.
sanitized = body
}
return &models.ObjectSummary{
return &models.EntitySummary{
Kind: models.StandardKindSVG,
Name: guessNameFromUID(uid),
UID: uid,

View File

@ -1,46 +0,0 @@
package objectdummyserver
import (
"context"
"fmt"
"github.com/grafana/grafana/pkg/services/store/object"
)
// Make sure we implement both store + admin
var _ object.ObjectStoreServer = &fakeObjectStore{}
var _ object.ObjectStoreAdminServer = &fakeObjectStore{}
func ProvideFakeObjectServer() object.ObjectStoreServer {
return &fakeObjectStore{}
}
type fakeObjectStore struct{}
func (i fakeObjectStore) AdminWrite(ctx context.Context, r *object.AdminWriteObjectRequest) (*object.WriteObjectResponse, error) {
return nil, fmt.Errorf("unimplemented")
}
func (i fakeObjectStore) Write(ctx context.Context, r *object.WriteObjectRequest) (*object.WriteObjectResponse, error) {
return nil, fmt.Errorf("unimplemented")
}
func (i fakeObjectStore) Read(ctx context.Context, r *object.ReadObjectRequest) (*object.ReadObjectResponse, error) {
return nil, fmt.Errorf("unimplemented")
}
func (i fakeObjectStore) BatchRead(ctx context.Context, batchR *object.BatchReadObjectRequest) (*object.BatchReadObjectResponse, error) {
return nil, fmt.Errorf("unimplemented")
}
func (i fakeObjectStore) Delete(ctx context.Context, r *object.DeleteObjectRequest) (*object.DeleteObjectResponse, error) {
return nil, fmt.Errorf("unimplemented")
}
func (i fakeObjectStore) History(ctx context.Context, r *object.ObjectHistoryRequest) (*object.ObjectHistoryResponse, error) {
return nil, fmt.Errorf("unimplemented")
}
func (i fakeObjectStore) Search(ctx context.Context, r *object.ObjectSearchRequest) (*object.ObjectSearchResponse, error) {
return nil, fmt.Errorf("unimplemented")
}

File diff suppressed because it is too large Load Diff

View File

@ -1,405 +0,0 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.21.9
// source: object.proto
package object
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// 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
// ObjectStoreClient is the client API for ObjectStore 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.
type ObjectStoreClient interface {
Read(ctx context.Context, in *ReadObjectRequest, opts ...grpc.CallOption) (*ReadObjectResponse, error)
BatchRead(ctx context.Context, in *BatchReadObjectRequest, opts ...grpc.CallOption) (*BatchReadObjectResponse, error)
Write(ctx context.Context, in *WriteObjectRequest, opts ...grpc.CallOption) (*WriteObjectResponse, error)
Delete(ctx context.Context, in *DeleteObjectRequest, opts ...grpc.CallOption) (*DeleteObjectResponse, error)
History(ctx context.Context, in *ObjectHistoryRequest, opts ...grpc.CallOption) (*ObjectHistoryResponse, error)
Search(ctx context.Context, in *ObjectSearchRequest, opts ...grpc.CallOption) (*ObjectSearchResponse, error)
// TEMPORARY... while we split this into a new service (see below)
AdminWrite(ctx context.Context, in *AdminWriteObjectRequest, opts ...grpc.CallOption) (*WriteObjectResponse, error)
}
type objectStoreClient struct {
cc grpc.ClientConnInterface
}
func NewObjectStoreClient(cc grpc.ClientConnInterface) ObjectStoreClient {
return &objectStoreClient{cc}
}
func (c *objectStoreClient) Read(ctx context.Context, in *ReadObjectRequest, opts ...grpc.CallOption) (*ReadObjectResponse, error) {
out := new(ReadObjectResponse)
err := c.cc.Invoke(ctx, "/object.ObjectStore/Read", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *objectStoreClient) BatchRead(ctx context.Context, in *BatchReadObjectRequest, opts ...grpc.CallOption) (*BatchReadObjectResponse, error) {
out := new(BatchReadObjectResponse)
err := c.cc.Invoke(ctx, "/object.ObjectStore/BatchRead", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *objectStoreClient) Write(ctx context.Context, in *WriteObjectRequest, opts ...grpc.CallOption) (*WriteObjectResponse, error) {
out := new(WriteObjectResponse)
err := c.cc.Invoke(ctx, "/object.ObjectStore/Write", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *objectStoreClient) Delete(ctx context.Context, in *DeleteObjectRequest, opts ...grpc.CallOption) (*DeleteObjectResponse, error) {
out := new(DeleteObjectResponse)
err := c.cc.Invoke(ctx, "/object.ObjectStore/Delete", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *objectStoreClient) History(ctx context.Context, in *ObjectHistoryRequest, opts ...grpc.CallOption) (*ObjectHistoryResponse, error) {
out := new(ObjectHistoryResponse)
err := c.cc.Invoke(ctx, "/object.ObjectStore/History", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *objectStoreClient) Search(ctx context.Context, in *ObjectSearchRequest, opts ...grpc.CallOption) (*ObjectSearchResponse, error) {
out := new(ObjectSearchResponse)
err := c.cc.Invoke(ctx, "/object.ObjectStore/Search", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *objectStoreClient) AdminWrite(ctx context.Context, in *AdminWriteObjectRequest, opts ...grpc.CallOption) (*WriteObjectResponse, error) {
out := new(WriteObjectResponse)
err := c.cc.Invoke(ctx, "/object.ObjectStore/AdminWrite", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ObjectStoreServer is the server API for ObjectStore service.
// All implementations should embed UnimplementedObjectStoreServer
// for forward compatibility
type ObjectStoreServer interface {
Read(context.Context, *ReadObjectRequest) (*ReadObjectResponse, error)
BatchRead(context.Context, *BatchReadObjectRequest) (*BatchReadObjectResponse, error)
Write(context.Context, *WriteObjectRequest) (*WriteObjectResponse, error)
Delete(context.Context, *DeleteObjectRequest) (*DeleteObjectResponse, error)
History(context.Context, *ObjectHistoryRequest) (*ObjectHistoryResponse, error)
Search(context.Context, *ObjectSearchRequest) (*ObjectSearchResponse, error)
// TEMPORARY... while we split this into a new service (see below)
AdminWrite(context.Context, *AdminWriteObjectRequest) (*WriteObjectResponse, error)
}
// UnimplementedObjectStoreServer should be embedded to have forward compatible implementations.
type UnimplementedObjectStoreServer struct {
}
func (UnimplementedObjectStoreServer) Read(context.Context, *ReadObjectRequest) (*ReadObjectResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Read not implemented")
}
func (UnimplementedObjectStoreServer) BatchRead(context.Context, *BatchReadObjectRequest) (*BatchReadObjectResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method BatchRead not implemented")
}
func (UnimplementedObjectStoreServer) Write(context.Context, *WriteObjectRequest) (*WriteObjectResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Write not implemented")
}
func (UnimplementedObjectStoreServer) Delete(context.Context, *DeleteObjectRequest) (*DeleteObjectResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented")
}
func (UnimplementedObjectStoreServer) History(context.Context, *ObjectHistoryRequest) (*ObjectHistoryResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method History not implemented")
}
func (UnimplementedObjectStoreServer) Search(context.Context, *ObjectSearchRequest) (*ObjectSearchResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Search not implemented")
}
func (UnimplementedObjectStoreServer) AdminWrite(context.Context, *AdminWriteObjectRequest) (*WriteObjectResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AdminWrite not implemented")
}
// UnsafeObjectStoreServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ObjectStoreServer will
// result in compilation errors.
type UnsafeObjectStoreServer interface {
mustEmbedUnimplementedObjectStoreServer()
}
func RegisterObjectStoreServer(s grpc.ServiceRegistrar, srv ObjectStoreServer) {
s.RegisterService(&ObjectStore_ServiceDesc, srv)
}
func _ObjectStore_Read_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ReadObjectRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ObjectStoreServer).Read(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/object.ObjectStore/Read",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ObjectStoreServer).Read(ctx, req.(*ReadObjectRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ObjectStore_BatchRead_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(BatchReadObjectRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ObjectStoreServer).BatchRead(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/object.ObjectStore/BatchRead",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ObjectStoreServer).BatchRead(ctx, req.(*BatchReadObjectRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ObjectStore_Write_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(WriteObjectRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ObjectStoreServer).Write(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/object.ObjectStore/Write",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ObjectStoreServer).Write(ctx, req.(*WriteObjectRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ObjectStore_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteObjectRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ObjectStoreServer).Delete(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/object.ObjectStore/Delete",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ObjectStoreServer).Delete(ctx, req.(*DeleteObjectRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ObjectStore_History_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ObjectHistoryRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ObjectStoreServer).History(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/object.ObjectStore/History",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ObjectStoreServer).History(ctx, req.(*ObjectHistoryRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ObjectStore_Search_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ObjectSearchRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ObjectStoreServer).Search(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/object.ObjectStore/Search",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ObjectStoreServer).Search(ctx, req.(*ObjectSearchRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ObjectStore_AdminWrite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AdminWriteObjectRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ObjectStoreServer).AdminWrite(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/object.ObjectStore/AdminWrite",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ObjectStoreServer).AdminWrite(ctx, req.(*AdminWriteObjectRequest))
}
return interceptor(ctx, in, info, handler)
}
// ObjectStore_ServiceDesc is the grpc.ServiceDesc for ObjectStore service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var ObjectStore_ServiceDesc = grpc.ServiceDesc{
ServiceName: "object.ObjectStore",
HandlerType: (*ObjectStoreServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Read",
Handler: _ObjectStore_Read_Handler,
},
{
MethodName: "BatchRead",
Handler: _ObjectStore_BatchRead_Handler,
},
{
MethodName: "Write",
Handler: _ObjectStore_Write_Handler,
},
{
MethodName: "Delete",
Handler: _ObjectStore_Delete_Handler,
},
{
MethodName: "History",
Handler: _ObjectStore_History_Handler,
},
{
MethodName: "Search",
Handler: _ObjectStore_Search_Handler,
},
{
MethodName: "AdminWrite",
Handler: _ObjectStore_AdminWrite_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "object.proto",
}
// ObjectStoreAdminClient is the client API for ObjectStoreAdmin 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.
type ObjectStoreAdminClient interface {
AdminWrite(ctx context.Context, in *AdminWriteObjectRequest, opts ...grpc.CallOption) (*WriteObjectResponse, error)
}
type objectStoreAdminClient struct {
cc grpc.ClientConnInterface
}
func NewObjectStoreAdminClient(cc grpc.ClientConnInterface) ObjectStoreAdminClient {
return &objectStoreAdminClient{cc}
}
func (c *objectStoreAdminClient) AdminWrite(ctx context.Context, in *AdminWriteObjectRequest, opts ...grpc.CallOption) (*WriteObjectResponse, error) {
out := new(WriteObjectResponse)
err := c.cc.Invoke(ctx, "/object.ObjectStoreAdmin/AdminWrite", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ObjectStoreAdminServer is the server API for ObjectStoreAdmin service.
// All implementations should embed UnimplementedObjectStoreAdminServer
// for forward compatibility
type ObjectStoreAdminServer interface {
AdminWrite(context.Context, *AdminWriteObjectRequest) (*WriteObjectResponse, error)
}
// UnimplementedObjectStoreAdminServer should be embedded to have forward compatible implementations.
type UnimplementedObjectStoreAdminServer struct {
}
func (UnimplementedObjectStoreAdminServer) AdminWrite(context.Context, *AdminWriteObjectRequest) (*WriteObjectResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AdminWrite not implemented")
}
// UnsafeObjectStoreAdminServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ObjectStoreAdminServer will
// result in compilation errors.
type UnsafeObjectStoreAdminServer interface {
mustEmbedUnimplementedObjectStoreAdminServer()
}
func RegisterObjectStoreAdminServer(s grpc.ServiceRegistrar, srv ObjectStoreAdminServer) {
s.RegisterService(&ObjectStoreAdmin_ServiceDesc, srv)
}
func _ObjectStoreAdmin_AdminWrite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AdminWriteObjectRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ObjectStoreAdminServer).AdminWrite(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/object.ObjectStoreAdmin/AdminWrite",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ObjectStoreAdminServer).AdminWrite(ctx, req.(*AdminWriteObjectRequest))
}
return interceptor(ctx, in, info, handler)
}
// ObjectStoreAdmin_ServiceDesc is the grpc.ServiceDesc for ObjectStoreAdmin service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var ObjectStoreAdmin_ServiceDesc = grpc.ServiceDesc{
ServiceName: "object.ObjectStoreAdmin",
HandlerType: (*ObjectStoreAdminServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "AdminWrite",
Handler: _ObjectStoreAdmin_AdminWrite_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "object.proto",
}

View File

@ -27,11 +27,11 @@ type ResolutionInfo struct {
Timestamp time.Time `json:"timestamp,omitempty"`
}
type ObjectReferenceResolver interface {
Resolve(ctx context.Context, ref *models.ObjectExternalReference) (ResolutionInfo, error)
type EntityReferenceResolver interface {
Resolve(ctx context.Context, ref *models.EntityExternalReference) (ResolutionInfo, error)
}
func ProvideObjectReferenceResolver(ds datasources.DataSourceService, pluginStore plugins.Store) ObjectReferenceResolver {
func ProvideEntityReferenceResolver(ds datasources.DataSourceService, pluginStore plugins.Store) EntityReferenceResolver {
return &standardReferenceResolver{
pluginStore: pluginStore,
ds: dsCache{
@ -46,7 +46,7 @@ type standardReferenceResolver struct {
ds dsCache
}
func (r *standardReferenceResolver) Resolve(ctx context.Context, ref *models.ObjectExternalReference) (ResolutionInfo, error) {
func (r *standardReferenceResolver) Resolve(ctx context.Context, ref *models.EntityExternalReference) (ResolutionInfo, error) {
if ref == nil {
return ResolutionInfo{OK: false, Timestamp: getNow()}, fmt.Errorf("ref is nil")
}
@ -73,7 +73,7 @@ func (r *standardReferenceResolver) Resolve(ctx context.Context, ref *models.Obj
}, nil
}
func (r *standardReferenceResolver) resolveDatasource(ctx context.Context, ref *models.ObjectExternalReference) (ResolutionInfo, error) {
func (r *standardReferenceResolver) resolveDatasource(ctx context.Context, ref *models.EntityExternalReference) (ResolutionInfo, error) {
ds, err := r.ds.getDS(ctx, ref.UID)
if err != nil || ds == nil || ds.UID == "" {
return ResolutionInfo{
@ -99,7 +99,7 @@ func (r *standardReferenceResolver) resolveDatasource(ctx context.Context, ref *
return res, nil
}
func (r *standardReferenceResolver) resolvePlugin(ctx context.Context, ref *models.ObjectExternalReference) (ResolutionInfo, error) {
func (r *standardReferenceResolver) resolvePlugin(ctx context.Context, ref *models.EntityExternalReference) (ResolutionInfo, error) {
p, ok := r.pluginStore.Plugin(ctx, ref.UID)
if !ok {
return ResolutionInfo{

View File

@ -45,18 +45,18 @@ func TestResolver(t *testing.T) {
pluginStore := plugins.FakePluginStore{
PluginList: []plugins.PluginDTO{p1, p2, p3},
}
provider := ProvideObjectReferenceResolver(ds, pluginStore)
provider := ProvideEntityReferenceResolver(ds, pluginStore)
scenarios := []struct {
name string
given *models.ObjectExternalReference
given *models.EntityExternalReference
expect ResolutionInfo
err string
ctx context.Context
}{
{
name: "Missing datasource without type",
given: &models.ObjectExternalReference{
given: &models.EntityExternalReference{
Kind: models.StandardKindDataSource,
UID: "xyz",
},
@ -65,7 +65,7 @@ func TestResolver(t *testing.T) {
},
{
name: "OK datasource",
given: &models.ObjectExternalReference{
given: &models.EntityExternalReference{
Kind: models.StandardKindDataSource,
Type: "influx",
UID: "influx-uid",
@ -75,7 +75,7 @@ func TestResolver(t *testing.T) {
},
{
name: "Get the default datasource",
given: &models.ObjectExternalReference{
given: &models.EntityExternalReference{
Kind: models.StandardKindDataSource,
},
expect: ResolutionInfo{
@ -87,7 +87,7 @@ func TestResolver(t *testing.T) {
},
{
name: "Get the default datasource (with type)",
given: &models.ObjectExternalReference{
given: &models.EntityExternalReference{
Kind: models.StandardKindDataSource,
Type: "influx",
},
@ -99,7 +99,7 @@ func TestResolver(t *testing.T) {
},
{
name: "Lookup by name",
given: &models.ObjectExternalReference{
given: &models.EntityExternalReference{
Kind: models.StandardKindDataSource,
UID: "Influx2",
},