Plugins: Move store init to dskit service (#111823)
This commit is contained in:
@@ -3,7 +3,9 @@ package datasource
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -20,14 +22,16 @@ import (
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
datasource "github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
query "github.com/grafana/grafana/pkg/apis/query/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/configprovider"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/sources"
|
||||
"github.com/grafana/grafana/pkg/promlib/models"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/query/queryschema"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/builder"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource/kinds"
|
||||
)
|
||||
|
||||
@@ -47,12 +51,12 @@ type DataSourceAPIBuilder struct {
|
||||
}
|
||||
|
||||
func RegisterAPIService(
|
||||
cfgProvider configprovider.ConfigProvider,
|
||||
features featuremgmt.FeatureToggles,
|
||||
apiRegistrar builder.APIRegistrar,
|
||||
pluginClient plugins.Client, // access to everything
|
||||
datasources ScopedPluginDatasourceProvider,
|
||||
contextProvider PluginContextWrapper,
|
||||
pluginStore pluginstore.Store,
|
||||
accessControl accesscontrol.AccessControl,
|
||||
reg prometheus.Registerer,
|
||||
) (*DataSourceAPIBuilder, error) {
|
||||
@@ -66,25 +70,43 @@ func RegisterAPIService(
|
||||
|
||||
var err error
|
||||
var builder *DataSourceAPIBuilder
|
||||
all := pluginStore.Plugins(context.Background(), plugins.TypeDataSource)
|
||||
|
||||
cfg, err := cfgProvider.Get(context.Background())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pluginJSONs, err := getCorePlugins(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ids := []string{
|
||||
"grafana-testdata-datasource",
|
||||
"prometheus",
|
||||
"graphite",
|
||||
}
|
||||
|
||||
for _, ds := range all {
|
||||
if explictPluginList && !slices.Contains(ids, ds.ID) {
|
||||
for _, pluginJSON := range pluginJSONs {
|
||||
if explictPluginList && !slices.Contains(ids, pluginJSON.ID) {
|
||||
continue // skip this one
|
||||
}
|
||||
|
||||
if !ds.Backend {
|
||||
if !pluginJSON.Backend {
|
||||
continue // skip frontend only plugins
|
||||
}
|
||||
|
||||
builder, err = NewDataSourceAPIBuilder(ds.JSONData,
|
||||
pluginClient,
|
||||
datasources.GetDatasourceProvider(ds.JSONData),
|
||||
if pluginJSON.Type != plugins.TypeDataSource {
|
||||
continue // skip non-datasource plugins
|
||||
}
|
||||
|
||||
client, ok := pluginClient.(PluginClient)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("plugin client is not a PluginClient: %T", pluginClient)
|
||||
}
|
||||
|
||||
builder, err = NewDataSourceAPIBuilder(pluginJSON,
|
||||
client,
|
||||
datasources.GetDatasourceProvider(pluginJSON),
|
||||
contextProvider,
|
||||
accessControl,
|
||||
features.IsEnabledGlobally(featuremgmt.FlagDatasourceQueryTypes),
|
||||
@@ -277,3 +299,22 @@ func (b *DataSourceAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.Op
|
||||
|
||||
return oas, err
|
||||
}
|
||||
|
||||
func getCorePlugins(cfg *setting.Cfg) ([]plugins.JSONData, error) {
|
||||
coreDataSourcesPath := filepath.Join(cfg.StaticRootPath, "app", "plugins", "datasource")
|
||||
coreDataSourcesSrc := sources.NewLocalSource(
|
||||
plugins.ClassCore,
|
||||
[]string{coreDataSourcesPath},
|
||||
)
|
||||
|
||||
res, err := coreDataSourcesSrc.Discover(context.Background())
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to load core data source plugins")
|
||||
}
|
||||
|
||||
pluginJSONs := make([]plugins.JSONData, 0, len(res))
|
||||
for _, p := range res {
|
||||
pluginJSONs = append(pluginJSONs, p.Primary.JSONData)
|
||||
}
|
||||
return pluginJSONs, nil
|
||||
}
|
||||
|
||||
@@ -3,9 +3,21 @@ package adapter
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/modules"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugininstaller"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||
"github.com/grafana/grafana/pkg/services/provisioning"
|
||||
)
|
||||
|
||||
const (
|
||||
// PluginStore is the module name for the plugin store service.
|
||||
PluginStore = pluginstore.ServiceName
|
||||
|
||||
// PluginInstaller is the module name for the plugin installer service.
|
||||
PluginInstaller = plugininstaller.ServiceName
|
||||
|
||||
// Provisioning is the module name for the provisioning service.
|
||||
Provisioning = provisioning.ServiceName
|
||||
|
||||
// Tracing is the module name for the tracing service.
|
||||
Tracing = tracing.ServiceName
|
||||
|
||||
@@ -29,7 +41,10 @@ func dependencyMap() map[string][]string {
|
||||
return map[string][]string{
|
||||
Tracing: {},
|
||||
GrafanaAPIServer: {Tracing},
|
||||
Core: {GrafanaAPIServer},
|
||||
PluginStore: {GrafanaAPIServer},
|
||||
PluginInstaller: {PluginStore},
|
||||
Provisioning: {PluginStore, PluginInstaller},
|
||||
Core: {GrafanaAPIServer, PluginStore, PluginInstaller, Provisioning},
|
||||
BackgroundServices: {Core},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
stopTimeout = 30 * time.Second
|
||||
stopTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
type ManagerAdapter struct {
|
||||
@@ -63,6 +63,7 @@ func (m *ManagerAdapter) starting(ctx context.Context) error {
|
||||
// skip disabled services
|
||||
if s, ok := bgSvc.(registry.CanBeDisabled); ok && s.IsDisabled() {
|
||||
logger.Debug("Skipping disabled service", "service", namedService.ServiceName())
|
||||
manager.RegisterInvisibleModule(namedService.ServiceName(), nil)
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,10 @@ var _ services.NamedService = &serviceAdapter{}
|
||||
// The adapter uses dskit's BasicService with a custom RunningFn:
|
||||
// - Starting phase: No-op, transitions immediately to Running
|
||||
// - Running phase: Delegates to the wrapped service's Run method
|
||||
// - Stopping phase: No-op, transitions immediately to Terminated/Failed
|
||||
// - Stopping phase: Closes the stop channel to signal the service to stop
|
||||
type serviceAdapter struct {
|
||||
*services.BasicService
|
||||
services.NamedService
|
||||
stopCh chan struct{}
|
||||
name string
|
||||
service registry.BackgroundService
|
||||
}
|
||||
@@ -36,8 +37,9 @@ func asNamedService(service registry.BackgroundService) *serviceAdapter {
|
||||
a := &serviceAdapter{
|
||||
name: name,
|
||||
service: service,
|
||||
stopCh: make(chan struct{}),
|
||||
}
|
||||
a.BasicService = services.NewBasicService(nil, a.run, nil).WithName(name)
|
||||
a.NamedService = services.NewBasicService(nil, a.running, a.stopping).WithName(name)
|
||||
return a
|
||||
}
|
||||
|
||||
@@ -46,13 +48,24 @@ func asNamedService(service registry.BackgroundService) *serviceAdapter {
|
||||
// background service's Run method. If the background service completes without
|
||||
// error, the adapter waits for context cancellation (service stop) before
|
||||
// transitioning to Stopping state, ensuring proper dskit service lifecycle.
|
||||
func (a *serviceAdapter) run(ctx context.Context) error {
|
||||
err := a.service.Run(ctx)
|
||||
func (a *serviceAdapter) running(ctx context.Context) error {
|
||||
serviceCtx, serviceCancel := context.WithCancel(ctx)
|
||||
go func() {
|
||||
<-a.stopCh
|
||||
serviceCancel()
|
||||
}()
|
||||
|
||||
err := a.service.Run(serviceCtx)
|
||||
if err != nil && !errors.Is(err, context.Canceled) {
|
||||
return err
|
||||
}
|
||||
// wait for context cancellation to transition to Stopping state.
|
||||
// this prevents the service from causing it's dependents to stop prematurely.
|
||||
<-ctx.Done()
|
||||
<-serviceCtx.Done()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *serviceAdapter) stopping(_ error) error {
|
||||
close(a.stopCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ func TestAsNamedService(t *testing.T) {
|
||||
adapter := asNamedService(mockSvc)
|
||||
|
||||
require.NotNil(t, adapter)
|
||||
require.NotNil(t, adapter.BasicService)
|
||||
require.NotNil(t, adapter.NamedService)
|
||||
require.Equal(t, mockSvc, adapter.service)
|
||||
|
||||
expectedName := reflect.TypeOf(mockSvc).String()
|
||||
|
||||
Reference in New Issue
Block a user