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) // Allow HTTP access to the object storage feature (dev only for now)
if hs.Features.IsEnabled(featuremgmt.FlagGrpcServer) { 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/querylibrary"
"github.com/grafana/grafana/pkg/services/searchV2" "github.com/grafana/grafana/pkg/services/searchV2"
"github.com/grafana/grafana/pkg/services/stats" "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"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
@ -145,7 +145,7 @@ type HTTPServer struct {
ThumbService thumbs.Service ThumbService thumbs.Service
ExportService export.ExportService ExportService export.ExportService
StorageService store.StorageService StorageService store.StorageService
httpObjectStore httpobjectstore.HTTPObjectStore httpEntityStore httpentitystore.HTTPEntityStore
SearchV2HTTPService searchV2.SearchHTTPService SearchV2HTTPService searchV2.SearchHTTPService
QueryLibraryHTTPService querylibrary.HTTPService QueryLibraryHTTPService querylibrary.HTTPService
QueryLibraryService querylibrary.Service QueryLibraryService querylibrary.Service
@ -234,7 +234,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
pluginsUpdateChecker *updatechecker.PluginsService, searchUsersService searchusers.Service, pluginsUpdateChecker *updatechecker.PluginsService, searchUsersService searchusers.Service,
dataSourcesService datasources.DataSourceService, queryDataService *query.Service, dataSourcesService datasources.DataSourceService, queryDataService *query.Service,
ldapGroups ldap.Groups, teamGuardian teamguardian.TeamGuardian, serviceaccountsService serviceaccounts.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, notificationService *notifications.NotificationService, dashboardService dashboards.DashboardService,
dashboardProvisioningService dashboards.DashboardProvisioningService, folderService folder.Service, dashboardProvisioningService dashboards.DashboardProvisioningService, folderService folder.Service,
datasourcePermissionsService permissions.DatasourcePermissionsService, alertNotificationService *alerting.AlertNotificationService, datasourcePermissionsService permissions.DatasourcePermissionsService, alertNotificationService *alerting.AlertNotificationService,
@ -312,7 +312,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
secretsMigrator: secretsMigrator, secretsMigrator: secretsMigrator,
secretsPluginMigrator: secretsPluginMigrator, secretsPluginMigrator: secretsPluginMigrator,
secretsStore: secretsStore, secretsStore: secretsStore,
httpObjectStore: httpObjectStore, httpEntityStore: httpEntityStore,
DataSourcesService: dataSourcesService, DataSourcesService: dataSourcesService,
searchUsersService: searchUsersService, searchUsersService: searchUsersService,
ldapGroups: ldapGroups, ldapGroups: ldapGroups,

View File

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

View File

@ -7,7 +7,7 @@ import (
) )
// Grafana resource name. See also: // 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 // NOTE: This structure/format is still under active development and is subject to change
type GRN struct { type GRN struct {
// TenantID contains the ID of the tenant (in hosted grafana) or // 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 // ExternalEntityReferenceRuntime_Transformer is a "type" under runtime
// UIDs include: joinByField, organize, seriesToColumns, etc // UIDs include: joinByField, organize, seriesToColumns, etc
ExternalEntityReferenceRuntime_Transformer = "transformer" 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 // 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 // Unique short id for this kind
ID string `json:"id,omitempty"` ID string `json:"id,omitempty"`
@ -82,10 +76,10 @@ type ObjectKindInfo struct {
MimeType string `json:"mimeType,omitempty"` 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. // 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 // This summary is used for a unified search and object listing
type ObjectSummary struct { type EntitySummary struct {
UID string `json:"uid,omitempty"` UID string `json:"uid,omitempty"`
Kind string `json:"kind,omitempty"` Kind string `json:"kind,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
@ -99,23 +93,23 @@ type ObjectSummary struct {
URL string `json:"URL,omitempty"` URL string `json:"URL,omitempty"`
// When errors exist // 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 // Optional field values. The schema will define and document possible values for a given kind
Fields map[string]interface{} `json:"fields,omitempty"` Fields map[string]interface{} `json:"fields,omitempty"`
// eg: panels within dashboard // eg: panels within dashboard
Nested []*ObjectSummary `json:"nested,omitempty"` Nested []*EntitySummary `json:"nested,omitempty"`
// Optional references to external things // Optional references to external things
References []*ObjectExternalReference `json:"references,omitempty"` References []*EntityExternalReference `json:"references,omitempty"`
// The summary can not be extended // The summary can not be extended
_ interface{} _ interface{}
} }
// This will likely get replaced with a more general error framework. // This will likely get replaced with a more general error framework.
type ObjectErrorInfo struct { type EntityErrorInfo struct {
// TODO: Match an error code registry? // TODO: Match an error code registry?
Code int64 `json:"code,omitempty"` Code int64 `json:"code,omitempty"`
@ -129,7 +123,7 @@ type ObjectErrorInfo struct {
// Reference to another object outside itself // Reference to another object outside itself
// This message is derived from the object body and can be used to search for references. // 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. // This does not represent a method to declare a reference to another object.
type ObjectExternalReference struct { type EntityExternalReference struct {
// datasource (instance), dashboard (instance), // datasource (instance), dashboard (instance),
Kind string `json:"kind,omitempty"` Kind string `json:"kind,omitempty"`
@ -140,6 +134,6 @@ type ObjectExternalReference struct {
UID string `json:"UID,omitempty"` 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 // 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" "github.com/grafana/grafana/pkg/services/serviceaccounts"
samanager "github.com/grafana/grafana/pkg/services/serviceaccounts/manager" samanager "github.com/grafana/grafana/pkg/services/serviceaccounts/manager"
"github.com/grafana/grafana/pkg/services/store" "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/store/sanitizer"
"github.com/grafana/grafana/pkg/services/thumbs" "github.com/grafana/grafana/pkg/services/thumbs"
"github.com/grafana/grafana/pkg/services/updatechecker" "github.com/grafana/grafana/pkg/services/updatechecker"
@ -52,7 +52,7 @@ func ProvideBackgroundServiceRegistry(
_ dashboardsnapshots.Service, _ *alerting.AlertNotificationService, _ dashboardsnapshots.Service, _ *alerting.AlertNotificationService,
_ serviceaccounts.Service, _ *guardian.Provider, _ serviceaccounts.Service, _ *guardian.Provider,
_ *plugindashboardsservice.DashboardUpdater, _ *sanitizer.Provider, _ *plugindashboardsservice.DashboardUpdater, _ *sanitizer.Provider,
_ *grpcserver.HealthService, _ object.ObjectStoreServer, _ *grpcserver.ReflectionService, _ *grpcserver.HealthService, _ entity.EntityStoreServer, _ *grpcserver.ReflectionService,
) *BackgroundServiceRegistry { ) *BackgroundServiceRegistry {
return NewBackgroundServiceRegistry( return NewBackgroundServiceRegistry(
httpServer, httpServer,

View File

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

View File

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

View File

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

View File

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

View File

@ -21,7 +21,7 @@ import (
"github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/playlist" "github.com/grafana/grafana/pkg/services/playlist"
"github.com/grafana/grafana/pkg/services/store" "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" "github.com/grafana/grafana/pkg/setting"
) )
@ -159,7 +159,7 @@ type StandardExport struct {
playlistService playlist.Service playlistService playlist.Service
orgService org.Service orgService org.Service
datasourceService datasources.DataSourceService datasourceService datasources.DataSourceService
store object.ObjectStoreServer store entity.EntityStoreServer
// updated with mutex // updated with mutex
exportJob Job exportJob Job
@ -167,7 +167,7 @@ type StandardExport struct {
func ProvideService(db db.DB, features featuremgmt.FeatureToggles, gl *live.GrafanaLive, cfg *setting.Cfg, func ProvideService(db db.DB, features featuremgmt.FeatureToggles, gl *live.GrafanaLive, cfg *setting.Cfg,
dashboardsnapshotsService dashboardsnapshots.Service, playlistService playlist.Service, orgService org.Service, 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) { if !features.IsEnabled(featuremgmt.FlagExport) {
return &StubExport{} return &StubExport{}
} }
@ -234,7 +234,7 @@ func (ex *StandardExport) HandleRequestExport(c *models.ReqContext) response.Res
case "dummy": case "dummy":
job, err = startDummyExportJob(cfg, broadcast) job, err = startDummyExportJob(cfg, broadcast)
case "objectStore": 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": case "git":
dir := filepath.Join(ex.dataDir, "export_git", fmt.Sprintf("git_%d", time.Now().Unix())) dir := filepath.Join(ex.dataDir, "export_git", fmt.Sprintf("git_%d", time.Now().Unix()))
if err := os.MkdirAll(dir, os.ModePerm); err != nil { 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/playlist"
"github.com/grafana/grafana/pkg/services/sqlstore/session" "github.com/grafana/grafana/pkg/services/sqlstore/session"
objectstore "github.com/grafana/grafana/pkg/services/store" 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" "github.com/grafana/grafana/pkg/services/user"
) )
@ -21,7 +21,7 @@ import (
type objectStoreImpl struct { type objectStoreImpl struct {
sess *session.SessionDB sess *session.SessionDB
sqlimpl *Service sqlimpl *Service
objectstore object.ObjectStoreServer objectstore entity.EntityStoreServer
} }
var _ playlist.Service = &objectStoreImpl{} var _ playlist.Service = &objectStoreImpl{}
@ -55,8 +55,8 @@ func (s *objectStoreImpl) sync() {
return return
} }
body, _ := json.Marshal(dto) body, _ := json.Marshal(dto)
_, _ = s.objectstore.Write(ctx, &object.WriteObjectRequest{ _, _ = s.objectstore.Write(ctx, &entity.WriteEntityRequest{
GRN: &object.GRN{ GRN: &entity.GRN{
TenantId: info.OrgID, TenantId: info.OrgID,
UID: info.UID, UID: info.UID,
Kind: models.StandardKindPlaylist, Kind: models.StandardKindPlaylist,
@ -73,8 +73,8 @@ func (s *objectStoreImpl) Create(ctx context.Context, cmd *playlist.CreatePlayli
if err != nil { if err != nil {
return rsp, fmt.Errorf("unable to write playlist to store") return rsp, fmt.Errorf("unable to write playlist to store")
} }
_, err = s.objectstore.Write(ctx, &object.WriteObjectRequest{ _, err = s.objectstore.Write(ctx, &entity.WriteEntityRequest{
GRN: &object.GRN{ GRN: &entity.GRN{
Kind: models.StandardKindPlaylist, Kind: models.StandardKindPlaylist,
UID: rsp.UID, UID: rsp.UID,
}, },
@ -94,8 +94,8 @@ func (s *objectStoreImpl) Update(ctx context.Context, cmd *playlist.UpdatePlayli
if err != nil { if err != nil {
return rsp, fmt.Errorf("unable to write playlist to store") return rsp, fmt.Errorf("unable to write playlist to store")
} }
_, err = s.objectstore.Write(ctx, &object.WriteObjectRequest{ _, err = s.objectstore.Write(ctx, &entity.WriteEntityRequest{
GRN: &object.GRN{ GRN: &entity.GRN{
UID: rsp.Uid, UID: rsp.Uid,
Kind: models.StandardKindPlaylist, 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 { func (s *objectStoreImpl) Delete(ctx context.Context, cmd *playlist.DeletePlaylistCommand) error {
err := s.sqlimpl.store.Delete(ctx, cmd) err := s.sqlimpl.store.Delete(ctx, cmd)
if err == nil { if err == nil {
_, err = s.objectstore.Delete(ctx, &object.DeleteObjectRequest{ _, err = s.objectstore.Delete(ctx, &entity.DeleteEntityRequest{
GRN: &object.GRN{ GRN: &entity.GRN{
UID: cmd.UID, UID: cmd.UID,
Kind: models.StandardKindPlaylist, 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) { func (s *objectStoreImpl) Get(ctx context.Context, q *playlist.GetPlaylistByUidQuery) (*playlist.PlaylistDTO, error) {
rsp, err := s.objectstore.Read(ctx, &object.ReadObjectRequest{ rsp, err := s.objectstore.Read(ctx, &entity.ReadEntityRequest{
GRN: &object.GRN{ GRN: &entity.GRN{
UID: q.UID, UID: q.UID,
Kind: models.StandardKindPlaylist, Kind: models.StandardKindPlaylist,
}, },
@ -152,20 +152,20 @@ func (s *objectStoreImpl) Get(ctx context.Context, q *playlist.GetPlaylistByUidQ
if err != nil { if err != nil {
return nil, err 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") return nil, fmt.Errorf("missing object")
} }
// Get the object from payload // Get the object from payload
found := &playlist.PlaylistDTO{} found := &playlist.PlaylistDTO{}
err = json.Unmarshal(rsp.Object.Body, found) err = json.Unmarshal(rsp.Entity.Body, found)
return found, err return found, err
} }
func (s *objectStoreImpl) Search(ctx context.Context, q *playlist.GetPlaylistsQuery) (playlist.Playlists, error) { func (s *objectStoreImpl) Search(ctx context.Context, q *playlist.GetPlaylistsQuery) (playlist.Playlists, error) {
playlists := make(playlist.Playlists, 0) 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}, Kind: []string{models.StandardKindPlaylist},
WithBody: true, WithBody: true,
Limit: 1000, Limit: 1000,

View File

@ -6,7 +6,7 @@ import (
"github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/playlist" "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 { type Service struct {
@ -15,7 +15,7 @@ type Service struct {
var _ playlist.Service = &Service{} 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 var sqlstore store
// 🐢🐢🐢 pick the store // 🐢🐢🐢 pick the store

View File

@ -54,7 +54,7 @@ type dashboard struct {
updated time.Time updated time.Time
// Use generic structure // Use generic structure
summary *models.ObjectSummary summary *models.EntitySummary
} }
// buildSignal is sent when search index is accessed in organization for which // 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: "", slug: "",
created: time.Now(), created: time.Now(),
updated: time.Now(), updated: time.Now(),
summary: &models.ObjectSummary{ summary: &models.EntitySummary{
//ID: 0, //ID: 0,
Name: "General", Name: "General",
}, },

View File

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

View File

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

View File

@ -1,11 +1,11 @@
package objectdummyserver package dummy
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"testing" "testing"
"github.com/grafana/grafana/pkg/services/store/object" "github.com/grafana/grafana/pkg/services/store/entity"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -16,8 +16,8 @@ func TestRawEncoders(t *testing.T) {
}) })
require.NoError(t, err) require.NoError(t, err)
raw := &ObjectVersionWithBody{ raw := &EntityVersionWithBody{
&object.ObjectVersionInfo{ &entity.EntityVersionInfo{
Version: "A", Version: "A",
}, },
body, body,
@ -30,28 +30,28 @@ func TestRawEncoders(t *testing.T) {
fmt.Printf("expect: %s", str) fmt.Printf("expect: %s", str)
require.JSONEq(t, `{"info":{"version":"A"},"body":"eyJmaWVsZCI6MS4yMywiaGVsbG8iOiJ3b3JsZCJ9"}`, str) require.JSONEq(t, `{"info":{"version":"A"},"body":"eyJmaWVsZCI6MS4yMywiaGVsbG8iOiJ3b3JsZCJ9"}`, str)
copy := &ObjectVersionWithBody{} copy := &EntityVersionWithBody{}
err = json.Unmarshal(b, copy) err = json.Unmarshal(b, copy)
require.NoError(t, err) require.NoError(t, err)
} }
func TestRawObjectWithHistory(t *testing.T) { func TestRawEntityWithHistory(t *testing.T) {
body, err := json.Marshal(map[string]interface{}{ body, err := json.Marshal(map[string]interface{}{
"hello": "world", "hello": "world",
"field": 1.23, "field": 1.23,
}) })
require.NoError(t, err) require.NoError(t, err)
raw := &RawObjectWithHistory{ raw := &EntityWithHistory{
Object: &object.RawObject{ Entity: &entity.Entity{
GRN: &object.GRN{UID: "x"}, GRN: &entity.GRN{UID: "x"},
Version: "A", Version: "A",
Body: body, Body: body,
}, },
History: make([]*ObjectVersionWithBody, 0), History: make([]*EntityVersionWithBody, 0),
} }
raw.History = append(raw.History, &ObjectVersionWithBody{ raw.History = append(raw.History, &EntityVersionWithBody{
&object.ObjectVersionInfo{ &entity.EntityVersionInfo{
Version: "B", Version: "B",
}, },
body, body,
@ -63,7 +63,7 @@ func TestRawObjectWithHistory(t *testing.T) {
str := string(b) str := string(b)
//fmt.Printf("expect: %s", str) //fmt.Printf("expect: %s", str)
require.JSONEq(t, `{ require.JSONEq(t, `{
"object": { "entity": {
"GRN": { "GRN": {
"UID": "x" "UID": "x"
}, },
@ -83,7 +83,7 @@ func TestRawObjectWithHistory(t *testing.T) {
] ]
}`, str) }`, str)
copy := &ObjectVersionWithBody{} copy := &EntityVersionWithBody{}
err = json.Unmarshal(b, copy) err = json.Unmarshal(b, copy)
require.NoError(t, err) 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"; syntax = "proto3";
package object; package entity;
option go_package = "./;object"; option go_package = "./;entity";
message GRN { message GRN {
// the tenant/org id // the tenant/org id
int64 tenant_id = 1; 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. // will trigger additional indexing behavior.
string kind = 3; string kind = 3;
@ -16,21 +16,21 @@ message GRN {
string UID = 4; string UID = 4;
} }
// The canonical object/document data -- this represents the raw bytes and storage level metadata // The canonical entity/document data -- this represents the raw bytes and storage level metadata
message RawObject { message Entity {
// Object identifier // Entity identifier
GRN GRN = 1; 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; 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; int64 updated_at = 3;
// Who created the object // Who created the entity
string created_by = 4; string created_by = 4;
// Who updated the object // Who updated the entity
string updated_by = 5; string updated_by = 5;
// Content Length // Content Length
@ -39,7 +39,7 @@ message RawObject {
// MD5 digest of the body // MD5 digest of the body
string ETag = 7; 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; bytes body = 8;
// Folder UID // Folder UID
@ -48,29 +48,29 @@ message RawObject {
// Unique slug within folder (may be UID) // Unique slug within folder (may be UID)
string slug = 10; 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 // NOTE: currently managed by the dashboard+dashboard_version tables
string version = 11; string version = 11;
// External location info // External location info
ObjectOriginInfo origin = 12; EntityOriginInfo origin = 12;
} }
message ObjectOriginInfo { message EntityOriginInfo {
// NOTE: currently managed by the dashboard_provisioning table // NOTE: currently managed by the dashboard_provisioning table
string source = 1; string source = 1;
// Key in the upstream system // Key in the upstream system
string key = 2; 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; int64 time = 3;
} }
// Report error while working with objects // Report error while working with entitys
// NOTE: real systems at scale will contain errors. // NOTE: real systems at scale will contain errors.
message ObjectErrorInfo { message EntityErrorInfo {
// Match an error code registry? // Match an error code registry?
int64 code = 1; int64 code = 1;
@ -81,15 +81,15 @@ message ObjectErrorInfo {
bytes details_json = 3; bytes details_json = 3;
} }
// This is a subset of RawObject that does not include body or sync info // This is a subset of Entity that does not include body or sync info
message ObjectVersionInfo { message EntityVersionInfo {
// 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
string version = 1; 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; int64 updated_at = 2;
// Who updated the object // Who updated the entity
string updated_by = 3; string updated_by = 3;
// Content Length // Content Length
@ -108,8 +108,8 @@ message ObjectVersionInfo {
// Get request/response // Get request/response
//----------------------------------------------- //-----------------------------------------------
message ReadObjectRequest { message ReadEntityRequest {
// Object identifier // Entity identifier
GRN GRN = 1; GRN GRN = 1;
// Fetch an explicit version // Fetch an explicit version
@ -122,11 +122,11 @@ message ReadObjectRequest {
bool with_summary = 4; bool with_summary = 4;
} }
message ReadObjectResponse { message ReadEntityResponse {
// Object details with the body removed // Entity details with the body removed
RawObject object = 1; Entity entity = 1;
// Object summary as JSON // Entity summary as JSON
bytes summary_json = 2; bytes summary_json = 2;
} }
@ -134,29 +134,29 @@ message ReadObjectResponse {
// Make many read requests at once (by Kind+ID+version) // Make many read requests at once (by Kind+ID+version)
//------------------------------------------------------ //------------------------------------------------------
message BatchReadObjectRequest { message BatchReadEntityRequest {
repeated ReadObjectRequest batch = 1; repeated ReadEntityRequest batch = 1;
} }
message BatchReadObjectResponse { message BatchReadEntityResponse {
repeated ReadObjectResponse results = 1; repeated ReadEntityResponse results = 1;
} }
//----------------------------------------------- //-----------------------------------------------
// Write request/response // Write request/response
//----------------------------------------------- //-----------------------------------------------
message WriteObjectRequest { message WriteEntityRequest {
// Object identifier // Entity identifier
GRN GRN = 1; 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; string folder = 2;
// The raw object body // The raw entity body
bytes body = 3; bytes body = 3;
// Message that can be seen when exploring object history // Message that can be seen when exploring entity history
string comment = 4; string comment = 4;
// Used for optimistic locking. If missing, the previous version will be replaced regardless // 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 // This operation is useful when syncing a resource from external sources
// that have more accurate metadata information (git, or an archive). // that have more accurate metadata information (git, or an archive).
// This process can bypass the forced checks that // This process can bypass the forced checks that
message AdminWriteObjectRequest { message AdminWriteEntityRequest {
// Object identifier // Entity identifier
GRN GRN = 1; 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; string folder = 2;
// The raw object body // The raw entity body
bytes body = 3; bytes body = 3;
// Message that can be seen when exploring object history // Message that can be seen when exploring entity history
string comment = 4; 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 // Optional, if 0 it will use the current time
int64 created_at = 5; 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 // Optional, if empty it will use the current user
int64 updated_at = 6; int64 updated_at = 6;
// Who created the object // Who created the entity
// Optional, if 0 it will use the current time // Optional, if 0 it will use the current time
string created_by = 7; string created_by = 7;
// Who updated the object // Who updated the entity
// Optional, if empty it will use the current user // Optional, if empty it will use the current user
string updated_by = 8; string updated_by = 8;
@ -207,21 +207,21 @@ message AdminWriteObjectRequest {
// This will make sense for systems that manage history explicitly externallay // This will make sense for systems that manage history explicitly externallay
bool clear_history = 11; bool clear_history = 11;
// Optionally define where the object came from // Optionally define where the entity came from
ObjectOriginInfo origin = 12; EntityOriginInfo origin = 12;
} }
message WriteObjectResponse { message WriteEntityResponse {
// Error info -- if exists, the save did not happen // Error info -- if exists, the save did not happen
ObjectErrorInfo error = 1; EntityErrorInfo error = 1;
// Object identifier // Entity identifier
GRN GRN = 2; GRN GRN = 2;
// Object details with the body removed // Entity details with the body removed
ObjectVersionInfo object = 3; EntityVersionInfo entity = 3;
// Object summary as JSON // Entity summary as JSON
bytes summary_json = 4; bytes summary_json = 4;
// Status code // Status code
@ -240,15 +240,15 @@ message WriteObjectResponse {
// Delete request/response // Delete request/response
//----------------------------------------------- //-----------------------------------------------
message DeleteObjectRequest { message DeleteEntityRequest {
// Object identifier // Entity identifier
GRN GRN = 1; GRN GRN = 1;
// Used for optimistic locking. If missing, the previous version will be replaced regardless // Used for optimistic locking. If missing, the previous version will be replaced regardless
string previous_version = 3; string previous_version = 3;
} }
message DeleteObjectResponse { message DeleteEntityResponse {
bool OK = 1; bool OK = 1;
} }
@ -256,8 +256,8 @@ message DeleteObjectResponse {
// History request/response // History request/response
//----------------------------------------------- //-----------------------------------------------
message ObjectHistoryRequest { message EntityHistoryRequest {
// Object identifier // Entity identifier
GRN GRN = 1; GRN GRN = 1;
// Maximum number of items to return // Maximum number of items to return
@ -267,12 +267,12 @@ message ObjectHistoryRequest {
string next_page_token = 5; string next_page_token = 5;
} }
message ObjectHistoryResponse { message EntityHistoryResponse {
// Object identifier // Entity identifier
GRN GRN = 1; GRN GRN = 1;
// Object metadata without the raw bytes // Entity metadata without the raw bytes
repeated ObjectVersionInfo versions = 2; repeated EntityVersionInfo versions = 2;
// More results exist... pass this in the next request // More results exist... pass this in the next request
string next_page_token = 3; string next_page_token = 3;
@ -283,7 +283,7 @@ message ObjectHistoryResponse {
// List request/response // List request/response
//----------------------------------------------- //-----------------------------------------------
message ObjectSearchRequest { message EntitySearchRequest {
// Starting from the requested page (other query parameters must match!) // Starting from the requested page (other query parameters must match!)
string next_page_token = 1; string next_page_token = 1;
@ -315,24 +315,24 @@ message ObjectSearchRequest {
bool with_fields = 10; bool with_fields = 10;
} }
// Search result metadata for each object // Search result metadata for each entity
message ObjectSearchResult { message EntitySearchResult {
// Object identifier // Entity identifier
GRN GRN = 1; GRN GRN = 1;
// The current veresion of this object // The current veresion of this entity
string version = 2; string version = 2;
// Content Length // Content Length
int64 size = 3; 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; int64 updated_at = 4;
// Who updated the object // Who updated the entity
string updated_by = 5; string updated_by = 5;
// Optionally include the full object body // Optionally include the full entity body
bytes body = 6; bytes body = 6;
//---------------------------------------- //----------------------------------------
@ -357,12 +357,12 @@ message ObjectSearchResult {
// Optionally include extracted JSON // Optionally include extracted JSON
bytes fields_json = 12; bytes fields_json = 12;
// ObjectErrorInfo in json // EntityErrorInfo in json
bytes error_json = 13; bytes error_json = 13;
} }
message ObjectSearchResponse { message EntitySearchResponse {
repeated ObjectSearchResult results = 1; repeated EntitySearchResult results = 1;
// More results exist... pass this in the next request // More results exist... pass this in the next request
string next_page_token = 2; string next_page_token = 2;
@ -373,25 +373,25 @@ message ObjectSearchResponse {
// Storage interface // Storage interface
//----------------------------------------------- //-----------------------------------------------
// The object store provides a basic CRUD (+watch eventually) interface for generic objects // The entity store provides a basic CRUD (+watch eventually) interface for generic entitys
service ObjectStore { service EntityStore {
rpc Read(ReadObjectRequest) returns (ReadObjectResponse); rpc Read(ReadEntityRequest) returns (ReadEntityResponse);
rpc BatchRead(BatchReadObjectRequest) returns (BatchReadObjectResponse); rpc BatchRead(BatchReadEntityRequest) returns (BatchReadEntityResponse);
rpc Write(WriteObjectRequest) returns (WriteObjectResponse); rpc Write(WriteEntityRequest) returns (WriteEntityResponse);
rpc Delete(DeleteObjectRequest) returns (DeleteObjectResponse); rpc Delete(DeleteEntityRequest) returns (DeleteEntityResponse);
rpc History(ObjectHistoryRequest) returns (ObjectHistoryResponse); rpc History(EntityHistoryRequest) returns (EntityHistoryResponse);
rpc Search(ObjectSearchRequest) returns (ObjectSearchResponse); rpc Search(EntitySearchRequest) returns (EntitySearchResponse);
// Ideally an additional search endpoint with more flexibility to limit what you actually care about // 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 // 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) // 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 // more explicit control that can support bulk operations like efficient git sync
service ObjectStoreAdmin { service EntityStoreAdmin {
rpc AdminWrite(AdminWriteObjectRequest) returns (WriteObjectResponse); 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 ./ \ protoc -I ./ \
--go_out=${DST_DIR} \ --go_out=${DST_DIR} \
--go-grpc_out=${DST_DIR} --go-grpc_opt=require_unimplemented_servers=false \ --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 ( import (
"fmt" "fmt"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,16 +9,16 @@ import (
"github.com/grafana/grafana/pkg/services/store" "github.com/grafana/grafana/pkg/services/store"
) )
func GetObjectKindInfo() models.ObjectKindInfo { func GetEntityKindInfo() models.EntityKindInfo {
return models.ObjectKindInfo{ return models.EntityKindInfo{
ID: models.StandardKindDataFrame, ID: models.StandardKindDataFrame,
Name: "Data frame", Name: "Data frame",
Description: "Data frame", Description: "Data frame",
} }
} }
func GetObjectSummaryBuilder() models.ObjectSummaryBuilder { func GetEntitySummaryBuilder() models.EntitySummaryBuilder {
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) {
df := &data.Frame{} df := &data.Frame{}
err := json.Unmarshal(body, df) err := json.Unmarshal(body, df)
if err != nil { if err != nil {
@ -33,7 +33,7 @@ func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
summary := &models.ObjectSummary{ summary := &models.EntitySummary{
Kind: models.StandardKindDataFrame, Kind: models.StandardKindDataFrame,
Name: df.Name, Name: df.Name,
UID: uid, UID: uid,

View File

@ -23,7 +23,7 @@ func TestDataFrameSummary(t *testing.T) {
in, err := data.FrameToJSON(df, data.IncludeAll) in, err := data.FrameToJSON(df, data.IncludeAll)
require.NoError(t, err) 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.NoError(t, err)
require.Equal(t, in, out) // same json require.Equal(t, in, out) // same json

View File

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

View File

@ -13,15 +13,15 @@ type Model struct {
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
} }
func GetObjectKindInfo() models.ObjectKindInfo { func GetEntityKindInfo() models.EntityKindInfo {
return models.ObjectKindInfo{ return models.EntityKindInfo{
ID: models.StandardKindFolder, ID: models.StandardKindFolder,
Name: "Folder", Name: "Folder",
} }
} }
func GetObjectSummaryBuilder() models.ObjectSummaryBuilder { func GetEntitySummaryBuilder() models.EntitySummaryBuilder {
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) {
obj := &Model{} obj := &Model{}
err := json.Unmarshal(body, obj) err := json.Unmarshal(body, obj)
if err != nil { if err != nil {
@ -32,7 +32,7 @@ func GetObjectSummaryBuilder() models.ObjectSummaryBuilder {
obj.Name = store.GuessNameFromUID(uid) obj.Name = store.GuessNameFromUID(uid)
} }
summary := &models.ObjectSummary{ summary := &models.EntitySummary{
Kind: models.StandardKindFolder, Kind: models.StandardKindFolder,
Name: obj.Name, Name: obj.Name,
Description: obj.Description, Description: obj.Description,

View File

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

View File

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

View File

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

View File

@ -23,7 +23,7 @@ func TestDataFrameSummary(t *testing.T) {
in, err := data.FrameToJSON(df, data.IncludeAll) in, err := data.FrameToJSON(df, data.IncludeAll)
require.NoError(t, err) 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.NoError(t, err)
require.JSONEq(t, string(in), string(out)) // same json require.JSONEq(t, string(in), string(out)) // same json

View File

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

View File

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

View File

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

View File

@ -14,7 +14,7 @@ func TestPNGSummary(t *testing.T) {
img, err := base64.StdEncoding.DecodeString(gopher) img, err := base64.StdEncoding.DecodeString(gopher)
require.NoError(t, err) 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.NoError(t, err)
require.Equal(t, img, out) // same image require.Equal(t, img, out) // same image

View File

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

View File

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

View File

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

View File

@ -9,8 +9,8 @@ import (
"github.com/grafana/grafana/pkg/services/rendering" "github.com/grafana/grafana/pkg/services/rendering"
) )
func GetObjectKindInfo() models.ObjectKindInfo { func GetEntityKindInfo() models.EntityKindInfo {
return models.ObjectKindInfo{ return models.EntityKindInfo{
ID: models.StandardKindSVG, ID: models.StandardKindSVG,
Name: "SVG", Name: "SVG",
Description: "Scalable Vector Graphics", Description: "Scalable Vector Graphics",
@ -21,8 +21,8 @@ func GetObjectKindInfo() models.ObjectKindInfo {
} }
// SVG sanitizer based on the rendering service // SVG sanitizer based on the rendering service
func GetObjectSummaryBuilder(allowUnsanitizedSvgUpload bool, renderer rendering.Service) models.ObjectSummaryBuilder { func GetEntitySummaryBuilder(allowUnsanitizedSvgUpload bool, renderer rendering.Service) models.EntitySummaryBuilder {
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) {
if !IsSVG(body) { if !IsSVG(body) {
return nil, nil, fmt.Errorf("invalid svg") return nil, nil, fmt.Errorf("invalid svg")
} }
@ -45,7 +45,7 @@ func GetObjectSummaryBuilder(allowUnsanitizedSvgUpload bool, renderer rendering.
sanitized = body sanitized = body
} }
return &models.ObjectSummary{ return &models.EntitySummary{
Kind: models.StandardKindSVG, Kind: models.StandardKindSVG,
Name: guessNameFromUID(uid), Name: guessNameFromUID(uid),
UID: 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"` Timestamp time.Time `json:"timestamp,omitempty"`
} }
type ObjectReferenceResolver interface { type EntityReferenceResolver interface {
Resolve(ctx context.Context, ref *models.ObjectExternalReference) (ResolutionInfo, error) 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{ return &standardReferenceResolver{
pluginStore: pluginStore, pluginStore: pluginStore,
ds: dsCache{ ds: dsCache{
@ -46,7 +46,7 @@ type standardReferenceResolver struct {
ds dsCache 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 { if ref == nil {
return ResolutionInfo{OK: false, Timestamp: getNow()}, fmt.Errorf("ref is 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 }, 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) ds, err := r.ds.getDS(ctx, ref.UID)
if err != nil || ds == nil || ds.UID == "" { if err != nil || ds == nil || ds.UID == "" {
return ResolutionInfo{ return ResolutionInfo{
@ -99,7 +99,7 @@ func (r *standardReferenceResolver) resolveDatasource(ctx context.Context, ref *
return res, nil 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) p, ok := r.pluginStore.Plugin(ctx, ref.UID)
if !ok { if !ok {
return ResolutionInfo{ return ResolutionInfo{

View File

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