From 0d1462cbbbe1e4712170d946818c2299bbb0e8b1 Mon Sep 17 00:00:00 2001 From: Andres Martinez Gotor Date: Wed, 17 Jan 2024 09:22:51 +0100 Subject: [PATCH] Add real instances to testdata standalone API server (#80473) Co-authored-by: Will Browne --- .vscode/launch.json | 2 +- pkg/registry/apis/datasource/standalone.go | 54 +++--- .../apis/datasource/standalone_services.go | 177 ++++++++++++++++++ 3 files changed, 202 insertions(+), 31 deletions(-) create mode 100644 pkg/registry/apis/datasource/standalone_services.go diff --git a/.vscode/launch.json b/.vscode/launch.json index 51df62f0e34..708b555d30d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -19,7 +19,7 @@ "program": "${workspaceFolder}/pkg/cmd/grafana/", "env": {}, "cwd": "${workspaceFolder}", - "args": ["apiserver", "testdata.datasource.grafana.app"] + "args": ["apiserver", "--secure-port=8443", "testdata.datasource.grafana.app"] }, { "name": "Attach to Chrome", diff --git a/pkg/registry/apis/datasource/standalone.go b/pkg/registry/apis/datasource/standalone.go index d14e5d24826..46e6059ac01 100644 --- a/pkg/registry/apis/datasource/standalone.go +++ b/pkg/registry/apis/datasource/standalone.go @@ -1,13 +1,10 @@ package datasource import ( + "context" "fmt" - "time" - "github.com/grafana/grafana/pkg/plugins" - "github.com/grafana/grafana/pkg/services/accesscontrol/actest" - "github.com/grafana/grafana/pkg/services/datasources" - fakeDatasources "github.com/grafana/grafana/pkg/services/datasources/fakes" + "github.com/grafana/grafana/pkg/setting" testdatasource "github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource" ) @@ -19,33 +16,30 @@ func NewStandaloneDatasource(group string) (*DataSourceAPIBuilder, error) { if group != "testdata.datasource.grafana.app" { return nil, fmt.Errorf("only testadata is currently supported") } - - orgId := int64(1) pluginId := "grafana-testdata-datasource" - now := time.Now() - dss := []*datasources.DataSource{ - { - OrgID: orgId, // default -- used in the list command - Type: pluginId, - UID: "builtin", // fake for now - Created: now, - Updated: now, - Name: "Testdata (builtin)", - }, - { - OrgID: orgId, // default -- used in the list command - Type: pluginId, - UID: "PD8C576611E62080A", // match the gdev version - Created: now, - Updated: now, - Name: "gdev-testdata", - }, + + cfg, err := setting.NewCfgFromArgs(setting.CommandLineArgs{ + // TODO: Add support for args? + }) + if err != nil { + return nil, err + } + + accessControl, pluginstoreService, dsService, cacheServiceImpl, err := apiBuilderServices(cfg, pluginId) + if err != nil { + return nil, err } + + testdataPlugin, found := pluginstoreService.Plugin(context.Background(), pluginId) + if !found { + return nil, fmt.Errorf("plugin %s not found", pluginId) + } + return NewDataSourceAPIBuilder( - plugins.JSONData{ID: pluginId}, testdatasource.ProvideService(), - &fakeDatasources.FakeDataSourceService{DataSources: dss}, - &fakeDatasources.FakeCacheService{DataSources: dss}, - // Always allow... but currently not called in standalone! - &actest.FakeAccessControl{ExpectedEvaluate: true}, + testdataPlugin.JSONData, + testdatasource.ProvideService(), + dsService, + cacheServiceImpl, + accessControl, ) } diff --git a/pkg/registry/apis/datasource/standalone_services.go b/pkg/registry/apis/datasource/standalone_services.go new file mode 100644 index 00000000000..6087d8c30c7 --- /dev/null +++ b/pkg/registry/apis/datasource/standalone_services.go @@ -0,0 +1,177 @@ +package datasource + +import ( + "context" + "path/filepath" + + "github.com/grafana/grafana/pkg/api/routing" + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/infra/kvstore" + "github.com/grafana/grafana/pkg/infra/localcache" + "github.com/grafana/grafana/pkg/infra/tracing" + "github.com/grafana/grafana/pkg/infra/usagestats/service" + "github.com/grafana/grafana/pkg/plugins" + pCfg "github.com/grafana/grafana/pkg/plugins/config" + "github.com/grafana/grafana/pkg/plugins/manager/loader" + "github.com/grafana/grafana/pkg/plugins/manager/pipeline/bootstrap" + "github.com/grafana/grafana/pkg/plugins/manager/pipeline/discovery" + "github.com/grafana/grafana/pkg/plugins/manager/pipeline/initialization" + "github.com/grafana/grafana/pkg/plugins/manager/pipeline/termination" + "github.com/grafana/grafana/pkg/plugins/manager/pipeline/validation" + "github.com/grafana/grafana/pkg/plugins/manager/registry" + "github.com/grafana/grafana/pkg/plugins/manager/signature" + "github.com/grafana/grafana/pkg/plugins/manager/sources" + "github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" + "github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol" + "github.com/grafana/grafana/pkg/services/datasources/guardian" + datasourceService "github.com/grafana/grafana/pkg/services/datasources/service" + "github.com/grafana/grafana/pkg/services/encryption/provider" + encryptionService "github.com/grafana/grafana/pkg/services/encryption/service" + "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/grafana/grafana/pkg/services/hooks" + "github.com/grafana/grafana/pkg/services/kmsproviders/osskmsproviders" + "github.com/grafana/grafana/pkg/services/licensing" + "github.com/grafana/grafana/pkg/services/pluginsintegration/config" + "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore" + "github.com/grafana/grafana/pkg/services/quota/quotaimpl" + "github.com/grafana/grafana/pkg/services/secrets/database" + kvstoreService "github.com/grafana/grafana/pkg/services/secrets/kvstore" + "github.com/grafana/grafana/pkg/services/secrets/manager" + "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/sqlstore/migrations" + "github.com/grafana/grafana/pkg/services/supportbundles/bundleregistry" + "github.com/grafana/grafana/pkg/setting" +) + +func apiBuilderServices(cfg *setting.Cfg, pluginID string) ( + *acimpl.AccessControl, + *pluginstore.Service, + *datasourceService.Service, + *datasourceService.CacheServiceImpl, + error, +) { + accessControl := acimpl.ProvideAccessControl(cfg) + cacheService := localcache.ProvideService() + tracingService, err := tracing.ProvideService(cfg) + if err != nil { + return nil, nil, nil, nil, err + } + routeRegisterImpl := routing.ProvideRegister() + hooksService := hooks.ProvideService() + ossLicensingService := licensing.ProvideService(cfg, hooksService) + featureManager, err := featuremgmt.ProvideManagerService(cfg, ossLicensingService) + if err != nil { + return nil, nil, nil, nil, err + } + + inProcBus := bus.ProvideBus(tracingService) + ossMigrations := migrations.ProvideOSSMigrations() + sqlStore, err := sqlstore.ProvideService(cfg, ossMigrations, inProcBus, tracingService) + if err != nil { + return nil, nil, nil, nil, err + } + + kvStore := kvstore.ProvideService(sqlStore) + featureToggles := featuremgmt.ProvideToggles(featureManager) + acimplService, err := acimpl.ProvideService(cfg, sqlStore, routeRegisterImpl, cacheService, accessControl, featureToggles) + if err != nil { + return nil, nil, nil, nil, err + } + bundleregistryService := bundleregistry.ProvideService() + usageStats, err := service.ProvideService(cfg, kvStore, routeRegisterImpl, tracingService, accessControl, acimplService, bundleregistryService) + if err != nil { + return nil, nil, nil, nil, err + } + secretsStoreImpl := database.ProvideSecretsStore(sqlStore) + providerProvider := provider.ProvideEncryptionProvider() + serviceService, err := encryptionService.ProvideEncryptionService(providerProvider, usageStats, cfg) + if err != nil { + return nil, nil, nil, nil, err + } + osskmsprovidersService := osskmsproviders.ProvideService(serviceService, cfg, featureToggles) + secretsService, err := manager.ProvideSecretsService(secretsStoreImpl, osskmsprovidersService, serviceService, cfg, featureToggles, usageStats) + if err != nil { + return nil, nil, nil, nil, err + } + ossImpl := setting.ProvideProvider(cfg) + configCfg, err := config.ProvideConfig(ossImpl, cfg, featureToggles) + if err != nil { + return nil, nil, nil, nil, err + } + inMemory := registry.ProvideService() + quotaService := quotaimpl.ProvideService(sqlStore, cfg) + loaderLoader, err := createLoader(configCfg, inMemory) + if err != nil { + return nil, nil, nil, nil, err + } + pluginstoreService, err := pluginstore.ProvideService(inMemory, newPluginSource(cfg, pluginID), loaderLoader) + if err != nil { + return nil, nil, nil, nil, err + } + secretsKVStore, err := kvstoreService.ProvideService(sqlStore, secretsService, pluginstoreService, kvStore, featureToggles, cfg) + if err != nil { + return nil, nil, nil, nil, err + } + datasourcePermissionsService := ossaccesscontrol.ProvideDatasourcePermissionsService() + service13, err := datasourceService.ProvideService(sqlStore, secretsService, secretsKVStore, cfg, featureToggles, accessControl, datasourcePermissionsService, quotaService, pluginstoreService) + if err != nil { + return nil, nil, nil, nil, err + } + + ossProvider := guardian.ProvideGuardian() + cacheServiceImpl := datasourceService.ProvideCacheService(cacheService, sqlStore, ossProvider) + + return accessControl, pluginstoreService, service13, cacheServiceImpl, nil +} + +var _ sources.Registry = (*pluginSource)(nil) + +type pluginSource struct { + cfg *setting.Cfg + pluginID string +} + +func newPluginSource(cfg *setting.Cfg, pluginID string) *pluginSource { + return &pluginSource{ + cfg: cfg, + pluginID: pluginID, + } +} + +func (t *pluginSource) List(_ context.Context) []plugins.PluginSource { + p := filepath.Join(t.cfg.StaticRootPath, "app/plugins/datasource", t.pluginID) + return []plugins.PluginSource{sources.NewLocalSource(plugins.ClassCore, []string{p})} +} + +func createLoader(cfg *pCfg.Cfg, pr registry.Service) (loader.Service, error) { + d := discovery.New(cfg, discovery.Opts{ + FindFilterFuncs: []discovery.FindFilterFunc{ + func(ctx context.Context, _ plugins.Class, b []*plugins.FoundBundle) ([]*plugins.FoundBundle, error) { + return discovery.NewDuplicatePluginFilterStep(pr).Filter(ctx, b) + }, + }, + }) + b := bootstrap.New(cfg, bootstrap.Opts{ + DecorateFuncs: []bootstrap.DecorateFunc{}, // no decoration required + }) + v := validation.New(cfg, validation.Opts{ + ValidateFuncs: []validation.ValidateFunc{ + validation.SignatureValidationStep(signature.NewValidator(signature.NewUnsignedAuthorizer(cfg))), + }, + }) + i := initialization.New(cfg, initialization.Opts{ + InitializeFuncs: []initialization.InitializeFunc{ + initialization.PluginRegistrationStep(pr), + }, + }) + t, err := termination.New(cfg, termination.Opts{ + TerminateFuncs: []termination.TerminateFunc{ + termination.DeregisterStep(pr), + }, + }) + if err != nil { + return nil, err + } + + return loader.New(d, b, v, i, t), nil +}